DynamicProfileInfo.cpp 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLanguagePch.h"
  6. #if ENABLE_NATIVE_CODEGEN
  7. namespace Js
  8. {
  9. #ifdef DYNAMIC_PROFILE_STORAGE
  10. DynamicProfileInfo::DynamicProfileInfo()
  11. {
  12. hasFunctionBody = false;
  13. }
  14. #endif
  15. struct Allocation
  16. {
  17. uint offset;
  18. size_t size;
  19. };
  20. #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
  21. bool DynamicProfileInfo::NeedProfileInfoList()
  22. {
  23. #pragma prefast(suppress: 6235 6286, "(<non-zero constant> || <expression>) is always a non-zero constant. - This is wrong, DBG_DUMP is not set in some build variants")
  24. return DBG_DUMP
  25. #ifdef DYNAMIC_PROFILE_STORAGE
  26. || DynamicProfileStorage::IsEnabled()
  27. #endif
  28. #ifdef RUNTIME_DATA_COLLECTION
  29. || (Configuration::Global.flags.RuntimeDataOutputFile != nullptr)
  30. #endif
  31. ;
  32. }
  33. #endif
  34. void ArrayCallSiteInfo::SetIsNotNativeIntArray()
  35. {
  36. OUTPUT_TRACE_WITH_STACK(Js::NativeArrayConversionPhase, _u("SetIsNotNativeIntArray \n"));
  37. bits |= NotNativeIntBit;
  38. }
  39. void ArrayCallSiteInfo::SetIsNotNativeFloatArray()
  40. {
  41. OUTPUT_TRACE_WITH_STACK(Js::NativeArrayConversionPhase, _u("SetIsNotNativeFloatArray \n"));
  42. bits |= NotNativeFloatBit;
  43. }
  44. void ArrayCallSiteInfo::SetIsNotNativeArray()
  45. {
  46. OUTPUT_TRACE_WITH_STACK(Js::NativeArrayConversionPhase, _u("SetIsNotNativeArray \n"));
  47. bits = NotNativeIntBit | NotNativeFloatBit;
  48. }
  49. DynamicProfileInfo* DynamicProfileInfo::New(Recycler* recycler, FunctionBody* functionBody, bool persistsAcrossScriptContexts)
  50. {
  51. size_t totalAlloc = 0;
  52. Allocation batch[] =
  53. {
  54. { (uint)offsetof(DynamicProfileInfo, callSiteInfo), functionBody->GetProfiledCallSiteCount() * sizeof(CallSiteInfo) },
  55. { (uint)offsetof(DynamicProfileInfo, ldElemInfo), functionBody->GetProfiledLdElemCount() * sizeof(LdElemInfo) },
  56. { (uint)offsetof(DynamicProfileInfo, stElemInfo), functionBody->GetProfiledStElemCount() * sizeof(StElemInfo) },
  57. { (uint)offsetof(DynamicProfileInfo, arrayCallSiteInfo), functionBody->GetProfiledArrayCallSiteCount() * sizeof(ArrayCallSiteInfo) },
  58. { (uint)offsetof(DynamicProfileInfo, fldInfo), functionBody->GetProfiledFldCount() * sizeof(FldInfo) },
  59. { (uint)offsetof(DynamicProfileInfo, divideTypeInfo), functionBody->GetProfiledDivOrRemCount() * sizeof(ValueType) },
  60. { (uint)offsetof(DynamicProfileInfo, switchTypeInfo), functionBody->GetProfiledSwitchCount() * sizeof(ValueType)},
  61. { (uint)offsetof(DynamicProfileInfo, slotInfo), functionBody->GetProfiledSlotCount() * sizeof(ValueType) },
  62. { (uint)offsetof(DynamicProfileInfo, parameterInfo), functionBody->GetProfiledInParamsCount() * sizeof(ValueType) },
  63. { (uint)offsetof(DynamicProfileInfo, returnTypeInfo), functionBody->GetProfiledReturnTypeCount() * sizeof(ValueType) },
  64. { (uint)offsetof(DynamicProfileInfo, loopImplicitCallFlags), (EnableImplicitCallFlags(functionBody) ? (functionBody->GetLoopCount() * sizeof(ImplicitCallFlags)) : 0) },
  65. { (uint)offsetof(DynamicProfileInfo, loopFlags), functionBody->GetLoopCount() ? BVFixed::GetAllocSize(functionBody->GetLoopCount() * LoopFlags::COUNT) : 0 }
  66. };
  67. for (uint i = 0; i < _countof(batch); i++)
  68. {
  69. totalAlloc += batch[i].size;
  70. }
  71. DynamicProfileInfo* info = nullptr;
  72. // In the profile storage case (-only), always allocate a non-leaf profile
  73. // In the regular profile case, we need to allocate it as non-leaf only if it's
  74. // a profile being used in the in-memory cache. This is because in that case, the profile
  75. // also allocates dynamicProfileFunctionInfo, which it uses to match functions across
  76. // script contexts. In the normal case, since we don't allocate that structure, we
  77. // can be a leaf allocation.
  78. if (persistsAcrossScriptContexts)
  79. {
  80. info = RecyclerNewPlusZ(recycler, totalAlloc, DynamicProfileInfo, functionBody);
  81. #if DBG
  82. info->persistsAcrossScriptContexts = true;
  83. #endif
  84. }
  85. else
  86. {
  87. #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
  88. if (DynamicProfileInfo::NeedProfileInfoList())
  89. {
  90. info = RecyclerNewPlusZ(recycler, totalAlloc, DynamicProfileInfo, functionBody);
  91. }
  92. else
  93. #endif
  94. {
  95. info = RecyclerNewPlusLeafZ(recycler, totalAlloc, DynamicProfileInfo, functionBody);
  96. }
  97. }
  98. BYTE* current = (BYTE*)info + sizeof(DynamicProfileInfo);
  99. for (uint i = 0; i < _countof(batch); i++)
  100. {
  101. if (batch[i].size > 0)
  102. {
  103. Field(BYTE*)* field = (Field(BYTE*)*)(((BYTE*)info + batch[i].offset));
  104. *field = current;
  105. current += batch[i].size;
  106. }
  107. }
  108. Assert(current - reinterpret_cast<BYTE*>(info) - sizeof(DynamicProfileInfo) == totalAlloc);
  109. info->Initialize(functionBody);
  110. return info;
  111. }
  112. DynamicProfileInfo::DynamicProfileInfo(FunctionBody * functionBody)
  113. #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
  114. : functionBody(DynamicProfileInfo::NeedProfileInfoList() ? functionBody : nullptr)
  115. #endif
  116. {
  117. hasFunctionBody = true;
  118. #if DBG
  119. persistsAcrossScriptContexts = true;
  120. #endif
  121. }
  122. void DynamicProfileInfo::Initialize(FunctionBody *const functionBody)
  123. {
  124. // Need to make value types uninitialized, which is not equivalent to zero
  125. thisInfo.valueType = ValueType::Uninitialized;
  126. const BVIndex loopFlagsCount = functionBody->GetLoopCount() * LoopFlags::COUNT;
  127. if (loopFlagsCount)
  128. {
  129. this->loopFlags->Init(loopFlagsCount);
  130. LoopFlags defaultValues;
  131. for (uint i = 0; i < functionBody->GetLoopCount(); ++i)
  132. {
  133. this->loopFlags->SetRange(&defaultValues, i * LoopFlags::COUNT, LoopFlags::COUNT);
  134. }
  135. }
  136. for (ProfileId i = 0; i < functionBody->GetProfiledCallSiteCount(); ++i)
  137. {
  138. callSiteInfo[i].returnType = ValueType::Uninitialized;
  139. callSiteInfo[i].u.functionData.sourceId = NoSourceId;
  140. }
  141. for (ProfileId i = 0; i < functionBody->GetProfiledLdElemCount(); ++i)
  142. {
  143. ldElemInfo[i].arrayType = ValueType::Uninitialized;
  144. ldElemInfo[i].elemType = ValueType::Uninitialized;
  145. }
  146. for (ProfileId i = 0; i < functionBody->GetProfiledStElemCount(); ++i)
  147. {
  148. stElemInfo[i].arrayType = ValueType::Uninitialized;
  149. }
  150. for (uint i = 0; i < functionBody->GetProfiledFldCount(); ++i)
  151. {
  152. fldInfo[i].flags = FldInfo_NoInfo;
  153. fldInfo[i].valueType = ValueType::Uninitialized;
  154. fldInfo[i].polymorphicInlineCacheUtilization = PolymorphicInlineCacheUtilizationThreshold;
  155. }
  156. for (ProfileId i = 0; i < functionBody->GetProfiledDivOrRemCount(); ++i)
  157. {
  158. divideTypeInfo[i] = ValueType::Uninitialized;
  159. }
  160. for (ProfileId i = 0; i < functionBody->GetProfiledSwitchCount(); ++i)
  161. {
  162. switchTypeInfo[i] = ValueType::Uninitialized;
  163. }
  164. for (ProfileId i = 0; i < functionBody->GetProfiledSlotCount(); ++i)
  165. {
  166. slotInfo[i] = ValueType::Uninitialized;
  167. }
  168. for (ArgSlot i = 0; i < functionBody->GetProfiledInParamsCount(); ++i)
  169. {
  170. parameterInfo[i] = ValueType::Uninitialized;
  171. }
  172. for (ProfileId i = 0; i < functionBody->GetProfiledReturnTypeCount(); ++i)
  173. {
  174. returnTypeInfo[i] = ValueType::Uninitialized;
  175. }
  176. this->rejitCount = 0;
  177. this->bailOutOffsetForLastRejit = Js::Constants::NoByteCodeOffset;
  178. #if DBG
  179. for (ProfileId i = 0; i < functionBody->GetProfiledArrayCallSiteCount(); ++i)
  180. {
  181. arrayCallSiteInfo[i].functionNumber = functionBody->GetFunctionNumber();
  182. arrayCallSiteInfo[i].callSiteNumber = i;
  183. }
  184. #endif
  185. #if TTD_NATIVE_PROFILE_ARRAY_WORK_AROUND
  186. if(functionBody->GetScriptContext()->GetThreadContext()->IsRuntimeInTTDMode())
  187. {
  188. for(ProfileId i = 0; i < functionBody->GetProfiledArrayCallSiteCount(); ++i)
  189. {
  190. arrayCallSiteInfo[i].SetIsNotNativeArray();
  191. }
  192. }
  193. #endif
  194. }
  195. bool DynamicProfileInfo::IsEnabledForAtLeastOneFunction(const ScriptContext *const scriptContext)
  196. {
  197. return IsEnabled_OptionalFunctionBody(nullptr, scriptContext);
  198. }
  199. bool DynamicProfileInfo::IsEnabled(const FunctionBody *const functionBody)
  200. {
  201. Assert(functionBody);
  202. return (IsEnabled_OptionalFunctionBody(functionBody, functionBody->GetScriptContext())
  203. #ifdef ENABLE_WASM
  204. && !(PHASE_TRACE1(Js::WasmInOutPhase) && functionBody->IsWasmFunction())
  205. #endif
  206. );
  207. }
  208. bool DynamicProfileInfo::IsEnabled_OptionalFunctionBody(const FunctionBody *const functionBody, const ScriptContext *const scriptContext)
  209. {
  210. Assert(scriptContext);
  211. return
  212. !PHASE_OFF_OPTFUNC(DynamicProfilePhase, functionBody) &&
  213. (
  214. #if ENABLE_DEBUG_CONFIG_OPTIONS
  215. PHASE_FORCE_OPTFUNC(DynamicProfilePhase, functionBody) ||
  216. #else
  217. Js::Configuration::Global.flags.ForceDynamicProfile ||
  218. #endif
  219. !scriptContext->GetConfig()->IsNoNative() ||
  220. (functionBody && functionBody->IsInDebugMode())
  221. #ifdef DYNAMIC_PROFILE_STORAGE
  222. || DynamicProfileStorage::DoCollectInfo()
  223. #endif
  224. );
  225. }
  226. bool DynamicProfileInfo::IsEnabledForAtLeastOneFunction(const Js::Phase phase, const ScriptContext *const scriptContext)
  227. {
  228. return IsEnabled_OptionalFunctionBody(phase, nullptr, scriptContext);
  229. }
  230. bool DynamicProfileInfo::IsEnabled(const Js::Phase phase, const FunctionBody *const functionBody)
  231. {
  232. Assert(functionBody);
  233. return (IsEnabled_OptionalFunctionBody(phase, functionBody, functionBody->GetScriptContext())
  234. #ifdef ENABLE_WASM
  235. && !(PHASE_TRACE1(Js::WasmInOutPhase) && functionBody->IsWasmFunction())
  236. #endif
  237. );
  238. }
  239. bool DynamicProfileInfo::IsEnabled_OptionalFunctionBody(
  240. const Js::Phase phase,
  241. const FunctionBody *const functionBody,
  242. const ScriptContext *const scriptContext)
  243. {
  244. if (!DynamicProfileInfo::IsEnabled_OptionalFunctionBody(functionBody, scriptContext))
  245. {
  246. return false;
  247. }
  248. switch (phase)
  249. {
  250. case Phase::TypedArrayPhase:
  251. case Phase::AggressiveIntTypeSpecPhase:
  252. case Phase::CheckThisPhase:
  253. case Phase::ProfileBasedFldFastPathPhase:
  254. case Phase::ObjTypeSpecPhase:
  255. case Phase::ArrayCheckHoistPhase:
  256. case Phase::SwitchOptPhase:
  257. case Phase::FixedNewObjPhase:
  258. return !PHASE_OFF_PROFILED_BYTE_CODE_OPTFUNC(phase, functionBody);
  259. case Phase::NativeArrayPhase:
  260. case Phase::FloatTypeSpecPhase:
  261. return !PHASE_OFF_PROFILED_BYTE_CODE_OPTFUNC(phase, functionBody)
  262. #ifdef _M_IX86
  263. && AutoSystemInfo::Data.SSE2Available()
  264. #endif
  265. ;
  266. case Phase::InlinePhase:
  267. return !PHASE_OFF_PROFILED_BYTE_CODE_OPTFUNC(Phase::InlinePhase, functionBody);
  268. }
  269. return false;
  270. }
  271. bool DynamicProfileInfo::EnableImplicitCallFlags(const FunctionBody *const functionBody)
  272. {
  273. return DynamicProfileInfo::IsEnabled(functionBody);
  274. }
  275. #ifdef _M_IX86
  276. __declspec(naked)
  277. Var
  278. DynamicProfileInfo::EnsureDynamicProfileInfoThunk(RecyclableObject* function, CallInfo callInfo, ...)
  279. {
  280. __asm
  281. {
  282. push ebp
  283. mov ebp, esp
  284. push[esp + 8] // push function object
  285. call DynamicProfileInfo::EnsureDynamicProfileInfo;
  286. #ifdef _CONTROL_FLOW_GUARD
  287. // verify that the call target is valid
  288. mov ecx, eax
  289. call[__guard_check_icall_fptr]
  290. mov eax, ecx
  291. #endif
  292. pop ebp
  293. jmp eax
  294. }
  295. }
  296. #endif
  297. JavascriptMethod DynamicProfileInfo::EnsureDynamicProfileInfo(ScriptFunction * function)
  298. {
  299. // If we're creating a dynamic profile, make sure that the function
  300. // has an entry point and this entry point is the "default" entrypoint
  301. // created when a function body is created.
  302. Assert(function->GetEntryPointInfo() != nullptr);
  303. Assert(function->GetFunctionEntryPointInfo()->entryPointIndex == 0);
  304. FunctionBody * functionBody = function->GetFunctionBody();
  305. // This is used only if the first entry point codegen completes.
  306. // So there is no concurrency concern with background code gen thread modifying the entry point.
  307. EntryPointInfo * entryPoint = functionBody->GetEntryPointInfo(0);
  308. Assert(entryPoint == function->GetEntryPointInfo());
  309. Assert(entryPoint->IsCodeGenDone());
  310. JavascriptMethod directEntryPoint = entryPoint->jsMethod;
  311. // Check if it has changed already
  312. if (directEntryPoint == DynamicProfileInfo::EnsureDynamicProfileInfoThunk)
  313. {
  314. functionBody->EnsureDynamicProfileInfo();
  315. if (functionBody->GetScriptContext()->CurrentThunk == ProfileEntryThunk)
  316. {
  317. directEntryPoint = ProfileEntryThunk;
  318. }
  319. else
  320. {
  321. directEntryPoint = entryPoint->GetNativeEntrypoint();
  322. }
  323. entryPoint->jsMethod = directEntryPoint;
  324. }
  325. else
  326. {
  327. Assert(directEntryPoint == ProfileEntryThunk || functionBody->GetScriptContext()->IsNativeAddress((void*)directEntryPoint));
  328. Assert(functionBody->HasExecutionDynamicProfileInfo());
  329. }
  330. return function->UpdateThunkEntryPoint(static_cast<FunctionEntryPointInfo*>(entryPoint), directEntryPoint);
  331. }
  332. bool DynamicProfileInfo::HasLdFldCallSiteInfo() const
  333. {
  334. return bits.hasLdFldCallSite;
  335. }
  336. bool DynamicProfileInfo::RecordLdFldCallSiteInfo(FunctionBody* functionBody, RecyclableObject* callee, bool callApplyTarget)
  337. {
  338. auto SetBits = [&]() -> bool
  339. {
  340. this->bits.hasLdFldCallSite = true;
  341. this->currentInlinerVersion++; // we don't mind if this overflows
  342. return true;
  343. };
  344. FunctionInfo* calleeFunctionInfo = callee->GetTypeId() == TypeIds_Function ? JavascriptFunction::FromVar(callee)->GetFunctionInfo() : nullptr;
  345. if (calleeFunctionInfo == nullptr)
  346. {
  347. return false;
  348. }
  349. else if (!calleeFunctionInfo->HasBody())
  350. {
  351. // We can inline fastDOM getter/setter.
  352. // We can directly call Math.max/min as apply targets.
  353. if ((calleeFunctionInfo->GetAttributes() & Js::FunctionInfo::Attributes::NeedCrossSiteSecurityCheck) ||
  354. (callApplyTarget && (calleeFunctionInfo->GetAttributes() & Js::FunctionInfo::Attributes::BuiltInInlinableAsLdFldInlinee)))
  355. {
  356. if (functionBody->GetScriptContext() == callee->GetScriptContext())
  357. {
  358. return SetBits();
  359. }
  360. }
  361. return false;
  362. }
  363. else if (functionBody->CheckCalleeContextForInlining(calleeFunctionInfo->GetFunctionProxy()))
  364. {
  365. // If functionInfo !HasBody(), the previous 'else if' branch is executed; otherwise it has a body and therefore it has a proxy
  366. return SetBits();
  367. }
  368. return false;
  369. }
  370. void DynamicProfileInfo::RecordConstParameterAtCallSite(ProfileId callSiteId, int argNum)
  371. {
  372. Assert(argNum < Js::InlineeCallInfo::MaxInlineeArgoutCount);
  373. Assert(callSiteId < functionBody->GetProfiledCallSiteCount());
  374. callSiteInfo[callSiteId].isArgConstant = callSiteInfo[callSiteId].isArgConstant | (1 << argNum);
  375. }
  376. uint16 DynamicProfileInfo::GetConstantArgInfo(ProfileId callSiteId)
  377. {
  378. return callSiteInfo[callSiteId].isArgConstant;
  379. }
  380. #ifdef ASMJS_PLAT
  381. void DynamicProfileInfo::RecordAsmJsCallSiteInfo(FunctionBody* callerBody, ProfileId callSiteId, FunctionBody* calleeBody)
  382. {
  383. if (!callerBody || !callerBody->GetIsAsmjsMode() || !calleeBody || !calleeBody->GetIsAsmjsMode())
  384. {
  385. AssertMsg(UNREACHED, "Call to RecordAsmJsCallSiteInfo without two asm.js/wasm FunctionBody");
  386. return;
  387. }
  388. #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
  389. // If we persistsAcrossScriptContext, the dynamic profile info may be referred to by multiple function body from
  390. // different script context
  391. Assert(!DynamicProfileInfo::NeedProfileInfoList() || this->persistsAcrossScriptContexts || this->functionBody == callerBody);
  392. #endif
  393. bool doInline = true;
  394. // This is a hard limit as we only use 4 bits to encode the actual count in the InlineeCallInfo
  395. if (calleeBody->GetAsmJsFunctionInfo()->GetArgCount() > Js::InlineeCallInfo::MaxInlineeArgoutCount)
  396. {
  397. doInline = false;
  398. }
  399. // Mark the callsite bit where caller and callee is same function
  400. if (calleeBody == callerBody && callSiteId < 32)
  401. {
  402. this->m_recursiveInlineInfo = this->m_recursiveInlineInfo | (1 << callSiteId);
  403. }
  404. // TODO: support polymorphic inlining in wasm
  405. Assert(!callSiteInfo[callSiteId].isPolymorphic);
  406. Js::SourceId oldSourceId = callSiteInfo[callSiteId].u.functionData.sourceId;
  407. if (oldSourceId == InvalidSourceId)
  408. {
  409. return;
  410. }
  411. Js::LocalFunctionId oldFunctionId = callSiteInfo[callSiteId].u.functionData.functionId;
  412. Js::SourceId sourceId = InvalidSourceId;
  413. Js::LocalFunctionId functionId;
  414. // We can only inline function that are from the same script context
  415. if (callerBody->GetScriptContext() == calleeBody->GetScriptContext())
  416. {
  417. if (callerBody->GetSecondaryHostSourceContext() == calleeBody->GetSecondaryHostSourceContext())
  418. {
  419. if (callerBody->GetHostSourceContext() == calleeBody->GetHostSourceContext())
  420. {
  421. sourceId = CurrentSourceId; // Caller and callee in same file
  422. }
  423. else
  424. {
  425. sourceId = (Js::SourceId)calleeBody->GetHostSourceContext(); // Caller and callee in different files
  426. }
  427. functionId = calleeBody->GetLocalFunctionId();
  428. }
  429. else
  430. {
  431. // Pretend that we are cross context when call is crossing script file.
  432. functionId = CallSiteCrossContext;
  433. }
  434. }
  435. else
  436. {
  437. functionId = CallSiteCrossContext;
  438. }
  439. if (oldSourceId == NoSourceId)
  440. {
  441. callSiteInfo[callSiteId].u.functionData.sourceId = sourceId;
  442. callSiteInfo[callSiteId].u.functionData.functionId = functionId;
  443. this->currentInlinerVersion++; // we don't mind if this overflows
  444. }
  445. else if (oldSourceId != sourceId || oldFunctionId != functionId)
  446. {
  447. if (oldFunctionId != CallSiteMixed)
  448. {
  449. this->currentInlinerVersion++; // we don't mind if this overflows
  450. }
  451. callSiteInfo[callSiteId].u.functionData.functionId = CallSiteMixed;
  452. doInline = false;
  453. }
  454. callSiteInfo[callSiteId].isConstructorCall = false;
  455. callSiteInfo[callSiteId].dontInline = !doInline;
  456. callSiteInfo[callSiteId].ldFldInlineCacheId = Js::Constants::NoInlineCacheIndex;
  457. }
  458. #endif
  459. void DynamicProfileInfo::RecordCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, FunctionInfo* calleeFunctionInfo, JavascriptFunction* calleeFunction, ArgSlot actualArgCount, bool isConstructorCall, InlineCacheIndex ldFldInlineCacheId)
  460. {
  461. #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION)
  462. // If we persistsAcrossScriptContext, the dynamic profile info may be referred to by multiple function body from
  463. // different script context
  464. Assert(!DynamicProfileInfo::NeedProfileInfoList() || this->persistsAcrossScriptContexts || this->functionBody == functionBody);
  465. #endif
  466. bool doInline = true;
  467. // This is a hard limit as we only use 4 bits to encode the actual count in the InlineeCallInfo
  468. if (actualArgCount > Js::InlineeCallInfo::MaxInlineeArgoutCount)
  469. {
  470. doInline = false;
  471. }
  472. // Mark the callsite bit where caller and callee is same function
  473. if (calleeFunctionInfo && functionBody == calleeFunctionInfo->GetFunctionProxy() && callSiteId < 32)
  474. {
  475. this->m_recursiveInlineInfo = this->m_recursiveInlineInfo | (1 << callSiteId);
  476. }
  477. if (!callSiteInfo[callSiteId].isPolymorphic)
  478. {
  479. Js::SourceId oldSourceId = callSiteInfo[callSiteId].u.functionData.sourceId;
  480. if (oldSourceId == InvalidSourceId)
  481. {
  482. return;
  483. }
  484. Js::LocalFunctionId oldFunctionId = callSiteInfo[callSiteId].u.functionData.functionId;
  485. Js::SourceId sourceId = InvalidSourceId;
  486. Js::LocalFunctionId functionId;
  487. if (calleeFunctionInfo == nullptr)
  488. {
  489. functionId = CallSiteNonFunction;
  490. }
  491. else if (!calleeFunctionInfo->HasBody())
  492. {
  493. Assert(calleeFunction); // calleeFunction can only be passed as null if the calleeFunctionInfo was null (which is checked above)
  494. if (functionBody->GetScriptContext() == calleeFunction->GetScriptContext())
  495. {
  496. sourceId = BuiltInSourceId;
  497. functionId = calleeFunctionInfo->GetLocalFunctionId();
  498. }
  499. else
  500. {
  501. functionId = CallSiteCrossContext;
  502. }
  503. }
  504. else
  505. {
  506. // We can only inline function that are from the same script context. So only record that data
  507. // We're about to call this function so deserialize it right now
  508. FunctionProxy* calleeFunctionProxy = calleeFunctionInfo->GetFunctionProxy();
  509. if (functionBody->GetScriptContext() == calleeFunctionProxy->GetScriptContext())
  510. {
  511. if (functionBody->GetSecondaryHostSourceContext() == calleeFunctionProxy->GetSecondaryHostSourceContext())
  512. {
  513. if (functionBody->GetHostSourceContext() == calleeFunctionProxy->GetHostSourceContext())
  514. {
  515. sourceId = CurrentSourceId; // Caller and callee in same file
  516. }
  517. else
  518. {
  519. sourceId = (Js::SourceId)calleeFunctionProxy->GetHostSourceContext(); // Caller and callee in different files
  520. }
  521. functionId = calleeFunctionProxy->GetLocalFunctionId();
  522. }
  523. else if (calleeFunctionProxy->GetHostSourceContext() == Js::Constants::JsBuiltInSourceContext)
  524. {
  525. sourceId = JsBuiltInSourceId;
  526. functionId = calleeFunctionProxy->GetLocalFunctionId();
  527. }
  528. else
  529. {
  530. // Pretend that we are cross context when call is crossing script file.
  531. functionId = CallSiteCrossContext;
  532. }
  533. }
  534. else
  535. {
  536. functionId = CallSiteCrossContext;
  537. }
  538. }
  539. if (oldSourceId == NoSourceId)
  540. {
  541. callSiteInfo[callSiteId].u.functionData.sourceId = sourceId;
  542. callSiteInfo[callSiteId].u.functionData.functionId = functionId;
  543. this->currentInlinerVersion++; // we don't mind if this overflows
  544. }
  545. else if (oldSourceId != sourceId || oldFunctionId != functionId)
  546. {
  547. if (oldFunctionId != CallSiteMixed)
  548. {
  549. this->currentInlinerVersion++; // we don't mind if this overflows
  550. }
  551. if (doInline && IsPolymorphicCallSite(functionId, sourceId, oldFunctionId, oldSourceId))
  552. {
  553. CreatePolymorphicDynamicProfileCallSiteInfo(functionBody, callSiteId, functionId, oldFunctionId, sourceId, oldSourceId);
  554. }
  555. else
  556. {
  557. callSiteInfo[callSiteId].u.functionData.functionId = CallSiteMixed;
  558. }
  559. }
  560. callSiteInfo[callSiteId].isConstructorCall = isConstructorCall;
  561. callSiteInfo[callSiteId].dontInline = !doInline;
  562. callSiteInfo[callSiteId].ldFldInlineCacheId = ldFldInlineCacheId;
  563. }
  564. else
  565. {
  566. Assert(doInline);
  567. Assert(callSiteInfo[callSiteId].isConstructorCall == isConstructorCall);
  568. RecordPolymorphicCallSiteInfo(functionBody, callSiteId, calleeFunctionInfo);
  569. }
  570. return;
  571. }
  572. bool DynamicProfileInfo::IsPolymorphicCallSite(Js::LocalFunctionId curFunctionId, Js::SourceId curSourceId, Js::LocalFunctionId oldFunctionId, Js::SourceId oldSourceId)
  573. {
  574. AssertMsg(oldSourceId != NoSourceId, "There is no previous call in this callsite, we shouldn't be checking for polymorphic");
  575. if (oldSourceId == NoSourceId || oldSourceId == InvalidSourceId || oldSourceId == BuiltInSourceId)
  576. {
  577. return false;
  578. }
  579. if (curFunctionId == CallSiteCrossContext || curFunctionId == CallSiteNonFunction || oldFunctionId == CallSiteMixed || oldFunctionId == CallSiteCrossContext)
  580. {
  581. return false;
  582. }
  583. Assert(oldFunctionId != CallSiteNonFunction);
  584. Assert(curFunctionId != oldFunctionId || curSourceId != oldSourceId);
  585. return true;
  586. }
  587. void DynamicProfileInfo::CreatePolymorphicDynamicProfileCallSiteInfo(FunctionBody *funcBody, ProfileId callSiteId, Js::LocalFunctionId functionId, Js::LocalFunctionId oldFunctionId, Js::SourceId sourceId, Js::SourceId oldSourceId)
  588. {
  589. PolymorphicCallSiteInfo *localPolyCallSiteInfo = RecyclerNewStructZ(funcBody->GetScriptContext()->GetRecycler(), PolymorphicCallSiteInfo);
  590. Assert(maxPolymorphicInliningSize >= 2);
  591. localPolyCallSiteInfo->functionIds[0] = oldFunctionId;
  592. localPolyCallSiteInfo->functionIds[1] = functionId;
  593. localPolyCallSiteInfo->sourceIds[0] = oldSourceId;
  594. localPolyCallSiteInfo->sourceIds[1] = sourceId;
  595. localPolyCallSiteInfo->next = funcBody->GetPolymorphicCallSiteInfoHead();
  596. for (int i = 2; i < maxPolymorphicInliningSize; i++)
  597. {
  598. localPolyCallSiteInfo->functionIds[i] = CallSiteNoInfo;
  599. }
  600. callSiteInfo[callSiteId].isPolymorphic = true;
  601. callSiteInfo[callSiteId].u.polymorphicCallSiteInfo = localPolyCallSiteInfo;
  602. funcBody->SetPolymorphicCallSiteInfoHead(localPolyCallSiteInfo);
  603. }
  604. void DynamicProfileInfo::ResetAllPolymorphicCallSiteInfo()
  605. {
  606. if (dynamicProfileFunctionInfo)
  607. {
  608. for (ProfileId i = 0; i < dynamicProfileFunctionInfo->callSiteInfoCount; i++)
  609. {
  610. if (callSiteInfo[i].isPolymorphic)
  611. {
  612. ResetPolymorphicCallSiteInfo(i, CallSiteMixed);
  613. }
  614. }
  615. }
  616. }
  617. void DynamicProfileInfo::ResetPolymorphicCallSiteInfo(ProfileId callSiteId, Js::LocalFunctionId functionId)
  618. {
  619. callSiteInfo[callSiteId].isPolymorphic = false;
  620. callSiteInfo[callSiteId].u.functionData.sourceId = CurrentSourceId;
  621. callSiteInfo[callSiteId].u.functionData.functionId = functionId;
  622. this->currentInlinerVersion++;
  623. }
  624. void DynamicProfileInfo::SetFunctionIdSlotForNewPolymorphicCall(ProfileId callSiteId, Js::LocalFunctionId curFunctionId, Js::SourceId curSourceId, Js::FunctionBody *inliner)
  625. {
  626. for (int i = 0; i < maxPolymorphicInliningSize; i++)
  627. {
  628. if (callSiteInfo[callSiteId].u.polymorphicCallSiteInfo->functionIds[i] == curFunctionId &&
  629. callSiteInfo[callSiteId].u.polymorphicCallSiteInfo->sourceIds[i] == curSourceId)
  630. {
  631. // we have it already
  632. return;
  633. }
  634. else if (callSiteInfo[callSiteId].u.polymorphicCallSiteInfo->functionIds[i] == CallSiteNoInfo)
  635. {
  636. callSiteInfo[callSiteId].u.polymorphicCallSiteInfo->functionIds[i] = curFunctionId;
  637. callSiteInfo[callSiteId].u.polymorphicCallSiteInfo->sourceIds[i] = curSourceId;
  638. this->currentInlinerVersion++;
  639. return;
  640. }
  641. }
  642. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  643. if (Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::PolymorphicInlinePhase))
  644. {
  645. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  646. Output::Print(_u("INLINING (Polymorphic): More than 4 functions at this call site \t callSiteId: %d\t calleeFunctionId: %d TopFunc %s (%s)\n"),
  647. callSiteId,
  648. curFunctionId,
  649. inliner->GetDisplayName(),
  650. inliner->GetDebugNumberSet(debugStringBuffer)
  651. );
  652. Output::Flush();
  653. }
  654. #endif
  655. #ifdef PERF_HINT
  656. if (PHASE_TRACE1(Js::PerfHintPhase))
  657. {
  658. WritePerfHint(PerfHints::PolymorphicInilineCap, inliner);
  659. }
  660. #endif
  661. // We reached the max allowed to inline, no point in continuing collecting the information. Reset and move on.
  662. ResetPolymorphicCallSiteInfo(callSiteId, CallSiteMixed);
  663. }
  664. void DynamicProfileInfo::RecordPolymorphicCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, FunctionInfo * calleeFunctionInfo)
  665. {
  666. Js::LocalFunctionId functionId;
  667. if (calleeFunctionInfo == nullptr || !calleeFunctionInfo->HasBody())
  668. {
  669. return ResetPolymorphicCallSiteInfo(callSiteId, CallSiteMixed);
  670. }
  671. // We can only inline function that are from the same script context. So only record that data
  672. // We're about to call this function so deserialize it right now.
  673. FunctionProxy* calleeFunctionProxy = calleeFunctionInfo->GetFunctionProxy();
  674. if (functionBody->GetScriptContext() == calleeFunctionProxy->GetScriptContext())
  675. {
  676. if (functionBody->GetSecondaryHostSourceContext() == calleeFunctionProxy->GetSecondaryHostSourceContext())
  677. {
  678. Js::SourceId sourceId = (Js::SourceId)calleeFunctionProxy->GetHostSourceContext();
  679. if (functionBody->GetHostSourceContext() == sourceId) // if caller and callee in same file
  680. {
  681. sourceId = CurrentSourceId;
  682. }
  683. functionId = calleeFunctionProxy->GetLocalFunctionId();
  684. SetFunctionIdSlotForNewPolymorphicCall(callSiteId, functionId, sourceId, functionBody);
  685. return;
  686. }
  687. }
  688. // Pretend that we are cross context when call is crossing script file.
  689. ResetPolymorphicCallSiteInfo(callSiteId, CallSiteCrossContext);
  690. }
  691. /* static */
  692. bool DynamicProfileInfo::HasCallSiteInfo(FunctionBody* functionBody)
  693. {
  694. SourceContextInfo *sourceContextInfo = functionBody->GetSourceContextInfo();
  695. return !functionBody->GetScriptContext()->IsNoContextSourceContextInfo(sourceContextInfo);
  696. }
  697. bool DynamicProfileInfo::GetPolymorphicCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, bool *isConstructorCall, __inout_ecount(functionBodyArrayLength) FunctionBody** functionBodyArray, uint functionBodyArrayLength)
  698. {
  699. Assert(functionBody);
  700. const auto callSiteCount = functionBody->GetProfiledCallSiteCount();
  701. Assert(callSiteId < callSiteCount);
  702. Assert(functionBody->IsJsBuiltInCode() || functionBody->IsPublicLibraryCode() || HasCallSiteInfo(functionBody));
  703. Assert(functionBodyArray);
  704. Assert(functionBodyArrayLength == DynamicProfileInfo::maxPolymorphicInliningSize);
  705. *isConstructorCall = callSiteInfo[callSiteId].isConstructorCall;
  706. if (callSiteInfo[callSiteId].dontInline)
  707. {
  708. return false;
  709. }
  710. if (callSiteInfo[callSiteId].isPolymorphic)
  711. {
  712. PolymorphicCallSiteInfo *polymorphicCallSiteInfo = callSiteInfo[callSiteId].u.polymorphicCallSiteInfo;
  713. for (uint i = 0; i < functionBodyArrayLength; i++)
  714. {
  715. Js::LocalFunctionId localFunctionId;
  716. Js::SourceId localSourceId;
  717. if (!polymorphicCallSiteInfo->GetFunction(i, &localFunctionId, &localSourceId))
  718. {
  719. AssertMsg(i >= 2, "We found at least two function Body");
  720. return true;
  721. }
  722. FunctionBody* matchedFunctionBody;
  723. if (localSourceId == CurrentSourceId) // caller and callee in same file
  724. {
  725. matchedFunctionBody = functionBody->GetUtf8SourceInfo()->FindFunction(localFunctionId);
  726. if (!matchedFunctionBody)
  727. {
  728. return false;
  729. }
  730. functionBodyArray[i] = matchedFunctionBody;
  731. }
  732. else if (localSourceId == NoSourceId || localSourceId == InvalidSourceId)
  733. {
  734. return false;
  735. }
  736. else
  737. {
  738. // For call across files find the function from the right source
  739. typedef JsUtil::List<RecyclerWeakReference<Utf8SourceInfo>*, Recycler, false, Js::FreeListedRemovePolicy> SourceList;
  740. SourceList * sourceList = functionBody->GetScriptContext()->GetSourceList();
  741. bool found = false;
  742. for (int j = 0; j < sourceList->Count() && !found; j++)
  743. {
  744. if (sourceList->IsItemValid(j))
  745. {
  746. Utf8SourceInfo *srcInfo = sourceList->Item(j)->Get();
  747. if (srcInfo && srcInfo->GetHostSourceContext() == localSourceId)
  748. {
  749. matchedFunctionBody = srcInfo->FindFunction(localFunctionId);
  750. if (!matchedFunctionBody)
  751. {
  752. return false;
  753. }
  754. functionBodyArray[i] = matchedFunctionBody;
  755. found = true;
  756. }
  757. }
  758. }
  759. if (!found)
  760. {
  761. return false;
  762. }
  763. }
  764. }
  765. return true;
  766. }
  767. return false;
  768. }
  769. bool DynamicProfileInfo::HasCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId)
  770. {
  771. Assert(functionBody);
  772. const auto callSiteCount = functionBody->GetProfiledCallSiteCount();
  773. Assert(callSiteId < callSiteCount);
  774. Assert(HasCallSiteInfo(functionBody));
  775. if (callSiteInfo[callSiteId].isPolymorphic)
  776. {
  777. return true;
  778. }
  779. return callSiteInfo[callSiteId].u.functionData.sourceId != NoSourceId;
  780. }
  781. FunctionInfo * DynamicProfileInfo::GetCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, bool *isConstructorCall, bool *isPolymorphicCall)
  782. {
  783. Assert(functionBody);
  784. const auto callSiteCount = functionBody->GetProfiledCallSiteCount();
  785. Assert(callSiteId < callSiteCount);
  786. Assert(functionBody->IsJsBuiltInCode() || functionBody->IsPublicLibraryCode() || HasCallSiteInfo(functionBody));
  787. *isConstructorCall = callSiteInfo[callSiteId].isConstructorCall;
  788. if (callSiteInfo[callSiteId].dontInline)
  789. {
  790. return nullptr;
  791. }
  792. if (!callSiteInfo[callSiteId].isPolymorphic)
  793. {
  794. Js::SourceId sourceId = callSiteInfo[callSiteId].u.functionData.sourceId;
  795. Js::LocalFunctionId functionId = callSiteInfo[callSiteId].u.functionData.functionId;
  796. if (sourceId == BuiltInSourceId)
  797. {
  798. return JavascriptBuiltInFunction::GetFunctionInfo(functionId);
  799. }
  800. if (sourceId == CurrentSourceId) // caller and callee in same file
  801. {
  802. FunctionProxy *inlineeProxy = functionBody->GetUtf8SourceInfo()->FindFunction(functionId);
  803. return inlineeProxy ? inlineeProxy->GetFunctionInfo() : nullptr;
  804. }
  805. if (sourceId == JsBuiltInSourceId)
  806. {
  807. // For call across files find the function from the right source
  808. JsUtil::List<RecyclerWeakReference<Utf8SourceInfo>*, Recycler, false, Js::FreeListedRemovePolicy> * sourceList = functionBody->GetScriptContext()->GetSourceList();
  809. for (int i = 0; i < sourceList->Count(); i++)
  810. {
  811. if (sourceList->IsItemValid(i))
  812. {
  813. Utf8SourceInfo *srcInfo = sourceList->Item(i)->Get();
  814. if (srcInfo && srcInfo->GetHostSourceContext() == Js::Constants::JsBuiltInSourceContext)
  815. {
  816. FunctionProxy *inlineeProxy = srcInfo->FindFunction(functionId);
  817. if (inlineeProxy)
  818. {
  819. return inlineeProxy->GetFunctionInfo();
  820. }
  821. else
  822. {
  823. return nullptr;
  824. }
  825. }
  826. }
  827. }
  828. }
  829. if (sourceId != NoSourceId && sourceId != InvalidSourceId)
  830. {
  831. // For call across files find the function from the right source
  832. JsUtil::List<RecyclerWeakReference<Utf8SourceInfo>*, Recycler, false, Js::FreeListedRemovePolicy> * sourceList = functionBody->GetScriptContext()->GetSourceList();
  833. for (int i = 0; i < sourceList->Count(); i++)
  834. {
  835. if (sourceList->IsItemValid(i))
  836. {
  837. Utf8SourceInfo *srcInfo = sourceList->Item(i)->Get();
  838. if (srcInfo && srcInfo->GetHostSourceContext() == sourceId)
  839. {
  840. FunctionProxy *inlineeProxy = srcInfo->FindFunction(functionId);
  841. return inlineeProxy ? inlineeProxy->GetFunctionInfo() : nullptr;
  842. }
  843. }
  844. }
  845. }
  846. }
  847. else
  848. {
  849. *isPolymorphicCall = true;
  850. }
  851. return nullptr;
  852. }
  853. uint DynamicProfileInfo::GetLdFldCacheIndexFromCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId)
  854. {
  855. Assert(functionBody);
  856. const auto callSiteCount = functionBody->GetProfiledCallSiteCount();
  857. Assert(callSiteId < callSiteCount);
  858. Assert(functionBody->IsJsBuiltInCode() || functionBody->IsPublicLibraryCode() || HasCallSiteInfo(functionBody));
  859. return callSiteInfo[callSiteId].ldFldInlineCacheId;
  860. }
  861. void DynamicProfileInfo::RecordElementLoad(FunctionBody* functionBody, ProfileId ldElemId, const LdElemInfo& info)
  862. {
  863. Assert(ldElemId < functionBody->GetProfiledLdElemCount());
  864. Assert(info.WasProfiled());
  865. ldElemInfo[ldElemId].Merge(info);
  866. }
  867. void DynamicProfileInfo::RecordElementLoadAsProfiled(FunctionBody *const functionBody, const ProfileId ldElemId)
  868. {
  869. Assert(ldElemId < functionBody->GetProfiledLdElemCount());
  870. ldElemInfo[ldElemId].wasProfiled = true;
  871. }
  872. void DynamicProfileInfo::RecordElementStore(FunctionBody* functionBody, ProfileId stElemId, const StElemInfo& info)
  873. {
  874. Assert(stElemId < functionBody->GetProfiledStElemCount());
  875. Assert(info.WasProfiled());
  876. stElemInfo[stElemId].Merge(info);
  877. }
  878. void DynamicProfileInfo::RecordElementStoreAsProfiled(FunctionBody *const functionBody, const ProfileId stElemId)
  879. {
  880. Assert(stElemId < functionBody->GetProfiledStElemCount());
  881. stElemInfo[stElemId].wasProfiled = true;
  882. }
  883. ArrayCallSiteInfo * DynamicProfileInfo::GetArrayCallSiteInfo(FunctionBody *functionBody, ProfileId index) const
  884. {
  885. Assert(index < functionBody->GetProfiledArrayCallSiteCount());
  886. return &arrayCallSiteInfo[index];
  887. }
  888. void DynamicProfileInfo::RecordFieldAccess(FunctionBody* functionBody, uint fieldAccessId, Var object, FldInfoFlags flags)
  889. {
  890. Assert(fieldAccessId < functionBody->GetProfiledFldCount());
  891. FldInfoFlags oldFlags = fldInfo[fieldAccessId].flags;
  892. if (object) // if not provided, the saved value type is not changed
  893. {
  894. fldInfo[fieldAccessId].valueType = fldInfo[fieldAccessId].valueType.Merge(object);
  895. }
  896. const auto mergedFlags = MergeFldInfoFlags(oldFlags, flags);
  897. fldInfo[fieldAccessId].flags = mergedFlags;
  898. if (flags & FldInfo_Polymorphic)
  899. {
  900. bits.hasPolymorphicFldAccess = true;
  901. if (!(oldFlags & FldInfo_Polymorphic))
  902. {
  903. this->SetHasNewPolyFieldAccess(functionBody);
  904. }
  905. if (fldInfo[fieldAccessId].polymorphicInlineCacheUtilization < (PolymorphicInlineCacheUtilizationMaxValue - PolymorphicInlineCacheUtilizationIncrement))
  906. {
  907. fldInfo[fieldAccessId].polymorphicInlineCacheUtilization += PolymorphicInlineCacheUtilizationIncrement;
  908. }
  909. else
  910. {
  911. fldInfo[fieldAccessId].polymorphicInlineCacheUtilization = PolymorphicInlineCacheUtilizationMaxValue;
  912. }
  913. }
  914. else if (flags != FldInfo_NoInfo &&
  915. fldInfo[fieldAccessId].polymorphicInlineCacheUtilization != PolymorphicInlineCacheUtilizationMaxValue)
  916. {
  917. if (fldInfo[fieldAccessId].polymorphicInlineCacheUtilization > (PolymorphicInlineCacheUtilizationMinValue + PolymorphicInlineCacheUtilizationDecrement))
  918. {
  919. fldInfo[fieldAccessId].polymorphicInlineCacheUtilization -= PolymorphicInlineCacheUtilizationDecrement;
  920. }
  921. else
  922. {
  923. fldInfo[fieldAccessId].polymorphicInlineCacheUtilization = PolymorphicInlineCacheUtilizationMinValue;
  924. }
  925. }
  926. }
  927. void DynamicProfileInfo::RecordDivideResultType(FunctionBody* body, ProfileId divideId, Var object)
  928. {
  929. Assert(divideId < body->GetProfiledDivOrRemCount());
  930. divideTypeInfo[divideId] = divideTypeInfo[divideId].Merge(object);
  931. }
  932. // We are overloading the value types to store whether it is a mod by power of 2.
  933. // TaggedInt:
  934. void DynamicProfileInfo::RecordModulusOpType(FunctionBody* body,
  935. ProfileId profileId, bool isModByPowerOf2)
  936. {
  937. Assert(profileId < body->GetProfiledDivOrRemCount());
  938. /* allow one op of the modulus to be optimized - anyway */
  939. if (divideTypeInfo[profileId].IsUninitialized())
  940. {
  941. divideTypeInfo[profileId] = ValueType::GetInt(true);
  942. }
  943. else
  944. {
  945. if (isModByPowerOf2)
  946. {
  947. divideTypeInfo[profileId] = divideTypeInfo[profileId]
  948. .Merge(ValueType::GetInt(true));
  949. }
  950. else
  951. {
  952. divideTypeInfo[profileId] = divideTypeInfo[profileId]
  953. .Merge(ValueType::Float);
  954. }
  955. }
  956. }
  957. bool DynamicProfileInfo::IsModulusOpByPowerOf2(FunctionBody* body, ProfileId profileId) const
  958. {
  959. Assert(profileId < body->GetProfiledDivOrRemCount());
  960. return divideTypeInfo[profileId].IsLikelyTaggedInt();
  961. }
  962. ValueType DynamicProfileInfo::GetDivideResultType(FunctionBody* body, ProfileId divideId) const
  963. {
  964. Assert(divideId < body->GetProfiledDivOrRemCount());
  965. return divideTypeInfo[divideId];
  966. }
  967. void DynamicProfileInfo::RecordSwitchType(FunctionBody* body, ProfileId switchId, Var object)
  968. {
  969. Assert(switchId < body->GetProfiledSwitchCount());
  970. switchTypeInfo[switchId] = switchTypeInfo[switchId].Merge(object);
  971. }
  972. ValueType DynamicProfileInfo::GetSwitchType(FunctionBody* body, ProfileId switchId) const
  973. {
  974. Assert(switchId < body->GetProfiledSwitchCount());
  975. return switchTypeInfo[switchId];
  976. }
  977. void DynamicProfileInfo::SetHasNewPolyFieldAccess(FunctionBody *functionBody)
  978. {
  979. this->polymorphicCacheState = functionBody->GetScriptContext()->GetThreadContext()->GetNextPolymorphicCacheState();
  980. PHASE_PRINT_TRACE(
  981. Js::ObjTypeSpecPhase, functionBody,
  982. _u("New profile cache state: %d\n"), this->polymorphicCacheState);
  983. }
  984. void DynamicProfileInfo::RecordPolymorphicFieldAccess(FunctionBody* functionBody, uint fieldAccessId)
  985. {
  986. this->RecordFieldAccess(functionBody, fieldAccessId, nullptr, FldInfo_Polymorphic);
  987. }
  988. void DynamicProfileInfo::RecordSlotLoad(FunctionBody* functionBody, ProfileId slotLoadId, Var object)
  989. {
  990. Assert(slotLoadId < functionBody->GetProfiledSlotCount());
  991. slotInfo[slotLoadId] = slotInfo[slotLoadId].Merge(object);
  992. }
  993. FldInfoFlags DynamicProfileInfo::MergeFldInfoFlags(FldInfoFlags oldFlags, FldInfoFlags newFlags)
  994. {
  995. return static_cast<FldInfoFlags>(oldFlags | newFlags);
  996. }
  997. void DynamicProfileInfo::RecordParameterInfo(FunctionBody *functionBody, ArgSlot index, Var object)
  998. {
  999. Assert(this->parameterInfo != nullptr);
  1000. Assert(index < functionBody->GetProfiledInParamsCount());
  1001. parameterInfo[index] = parameterInfo[index].Merge(object);
  1002. }
  1003. ValueType DynamicProfileInfo::GetParameterInfo(FunctionBody* functionBody, ArgSlot index) const
  1004. {
  1005. Assert(this->parameterInfo != nullptr);
  1006. Assert(index < functionBody->GetProfiledInParamsCount());
  1007. return parameterInfo[index];
  1008. }
  1009. void DynamicProfileInfo::RecordReturnTypeOnCallSiteInfo(FunctionBody* functionBody, ProfileId callSiteId, Var object)
  1010. {
  1011. Assert(callSiteId < functionBody->GetProfiledCallSiteCount());
  1012. this->callSiteInfo[callSiteId].returnType = this->callSiteInfo[callSiteId].returnType.Merge(object);
  1013. }
  1014. void DynamicProfileInfo::RecordReturnType(FunctionBody* functionBody, ProfileId callSiteId, Var object)
  1015. {
  1016. Assert(callSiteId < functionBody->GetProfiledReturnTypeCount());
  1017. this->returnTypeInfo[callSiteId] = this->returnTypeInfo[callSiteId].Merge(object);
  1018. }
  1019. ValueType DynamicProfileInfo::GetReturnType(FunctionBody* functionBody, Js::OpCode opcode, ProfileId callSiteId) const
  1020. {
  1021. if (opcode < Js::OpCode::ProfiledReturnTypeCallI)
  1022. {
  1023. Assert(IsProfiledCallOp(opcode));
  1024. Assert(callSiteId < functionBody->GetProfiledCallSiteCount());
  1025. return this->callSiteInfo[callSiteId].returnType;
  1026. }
  1027. Assert(IsProfiledReturnTypeOp(opcode));
  1028. Assert(callSiteId < functionBody->GetProfiledReturnTypeCount());
  1029. return this->returnTypeInfo[callSiteId];
  1030. }
  1031. void DynamicProfileInfo::RecordThisInfo(Var object, ThisType thisType)
  1032. {
  1033. this->thisInfo.valueType = this->thisInfo.valueType.Merge(object);
  1034. this->thisInfo.thisType = max(this->thisInfo.thisType, thisType);
  1035. }
  1036. ThisInfo DynamicProfileInfo::GetThisInfo() const
  1037. {
  1038. return this->thisInfo;
  1039. }
  1040. void DynamicProfileInfo::RecordLoopImplicitCallFlags(FunctionBody* functionBody, uint loopNum, ImplicitCallFlags flags)
  1041. {
  1042. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(functionBody));
  1043. Assert(loopNum < functionBody->GetLoopCount());
  1044. this->loopImplicitCallFlags[loopNum] = (ImplicitCallFlags)(this->loopImplicitCallFlags[loopNum] | flags);
  1045. }
  1046. ImplicitCallFlags DynamicProfileInfo::GetLoopImplicitCallFlags(FunctionBody* functionBody, uint loopNum) const
  1047. {
  1048. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(functionBody));
  1049. Assert(loopNum < functionBody->GetLoopCount());
  1050. // Mask out the dispose implicit call. We would bailout on reentrant dispose,
  1051. // but it shouldn't affect optimization.
  1052. return (ImplicitCallFlags)(this->loopImplicitCallFlags[loopNum] & ImplicitCall_All);
  1053. }
  1054. void DynamicProfileInfo::RecordImplicitCallFlags(ImplicitCallFlags flags)
  1055. {
  1056. this->implicitCallFlags = (ImplicitCallFlags)(this->implicitCallFlags | flags);
  1057. }
  1058. ImplicitCallFlags DynamicProfileInfo::GetImplicitCallFlags() const
  1059. {
  1060. // Mask out the dispose implicit call. We would bailout on reentrant dispose,
  1061. // but it shouldn't affect optimization.
  1062. return (ImplicitCallFlags)(this->implicitCallFlags & ImplicitCall_All);
  1063. }
  1064. void DynamicProfileInfo::UpdateFunctionInfo(FunctionBody* functionBody, Recycler* recycler)
  1065. {
  1066. Assert(this->persistsAcrossScriptContexts);
  1067. if (!this->dynamicProfileFunctionInfo)
  1068. {
  1069. this->dynamicProfileFunctionInfo = RecyclerNewStructLeaf(recycler, DynamicProfileFunctionInfo);
  1070. }
  1071. this->dynamicProfileFunctionInfo->callSiteInfoCount = functionBody->GetProfiledCallSiteCount();
  1072. this->dynamicProfileFunctionInfo->paramInfoCount = functionBody->GetProfiledInParamsCount();
  1073. this->dynamicProfileFunctionInfo->divCount = functionBody->GetProfiledDivOrRemCount();
  1074. this->dynamicProfileFunctionInfo->switchCount = functionBody->GetProfiledSwitchCount();
  1075. this->dynamicProfileFunctionInfo->returnTypeInfoCount = functionBody->GetProfiledReturnTypeCount();
  1076. this->dynamicProfileFunctionInfo->loopCount = functionBody->GetLoopCount();
  1077. this->dynamicProfileFunctionInfo->ldElemInfoCount = functionBody->GetProfiledLdElemCount();
  1078. this->dynamicProfileFunctionInfo->stElemInfoCount = functionBody->GetProfiledStElemCount();
  1079. this->dynamicProfileFunctionInfo->arrayCallSiteCount = functionBody->GetProfiledArrayCallSiteCount();
  1080. this->dynamicProfileFunctionInfo->fldInfoCount = functionBody->GetProfiledFldCount();
  1081. this->dynamicProfileFunctionInfo->slotInfoCount = functionBody->GetProfiledSlotCount();
  1082. }
  1083. void DynamicProfileInfo::Save(ScriptContext * scriptContext)
  1084. {
  1085. // For now, we only support our local storage
  1086. #ifdef DYNAMIC_PROFILE_STORAGE
  1087. if (!DynamicProfileStorage::IsEnabled())
  1088. {
  1089. return;
  1090. }
  1091. if (scriptContext->GetSourceContextInfoMap() == nullptr)
  1092. {
  1093. // We don't have savable code
  1094. Assert(!scriptContext->GetProfileInfoList() || scriptContext->GetProfileInfoList()->Empty() || scriptContext->GetNoContextSourceContextInfo()->nextLocalFunctionId != 0);
  1095. return;
  1096. }
  1097. DynamicProfileInfo::UpdateSourceDynamicProfileManagers(scriptContext);
  1098. scriptContext->GetSourceContextInfoMap()->Map([&](DWORD_PTR dwHostSourceContext, SourceContextInfo * sourceContextInfo)
  1099. {
  1100. if (sourceContextInfo->sourceDynamicProfileManager != nullptr && sourceContextInfo->url != nullptr
  1101. && !sourceContextInfo->IsDynamic())
  1102. {
  1103. sourceContextInfo->sourceDynamicProfileManager->SaveToDynamicProfileStorage(sourceContextInfo->url);
  1104. }
  1105. });
  1106. #endif
  1107. }
  1108. bool DynamicProfileInfo::MatchFunctionBody(FunctionBody * functionBody)
  1109. {
  1110. // This function is called to set a function body to the dynamic profile loaded from cache.
  1111. // Need to verify that the function body matches with the profile info
  1112. Assert(this->dynamicProfileFunctionInfo);
  1113. if (this->dynamicProfileFunctionInfo->paramInfoCount != functionBody->GetProfiledInParamsCount()
  1114. || this->dynamicProfileFunctionInfo->ldElemInfoCount != functionBody->GetProfiledLdElemCount()
  1115. || this->dynamicProfileFunctionInfo->stElemInfoCount != functionBody->GetProfiledStElemCount()
  1116. || this->dynamicProfileFunctionInfo->arrayCallSiteCount != functionBody->GetProfiledArrayCallSiteCount()
  1117. || this->dynamicProfileFunctionInfo->fldInfoCount != functionBody->GetProfiledFldCount()
  1118. || this->dynamicProfileFunctionInfo->slotInfoCount != functionBody->GetProfiledSlotCount()
  1119. || this->dynamicProfileFunctionInfo->callSiteInfoCount != functionBody->GetProfiledCallSiteCount()
  1120. || this->dynamicProfileFunctionInfo->returnTypeInfoCount != functionBody->GetProfiledReturnTypeCount()
  1121. || this->dynamicProfileFunctionInfo->loopCount != functionBody->GetLoopCount()
  1122. || this->dynamicProfileFunctionInfo->switchCount != functionBody->GetProfiledSwitchCount()
  1123. || this->dynamicProfileFunctionInfo->divCount != functionBody->GetProfiledDivOrRemCount())
  1124. {
  1125. // Reject, the dynamic profile information doesn't match the function body
  1126. return false;
  1127. }
  1128. #ifdef DYNAMIC_PROFILE_STORAGE
  1129. this->functionBody = functionBody;
  1130. #endif
  1131. this->hasFunctionBody = true;
  1132. return true;
  1133. }
  1134. FldInfo * DynamicProfileInfo::GetFldInfo(FunctionBody* functionBody, uint fieldAccessId) const
  1135. {
  1136. Assert(fieldAccessId < functionBody->GetProfiledFldCount());
  1137. return &fldInfo[fieldAccessId];
  1138. }
  1139. ValueType DynamicProfileInfo::GetSlotLoad(FunctionBody* functionBody, ProfileId slotLoadId) const
  1140. {
  1141. Assert(slotLoadId < functionBody->GetProfiledSlotCount());
  1142. return slotInfo[slotLoadId];
  1143. }
  1144. FldInfoFlags DynamicProfileInfo::FldInfoFlagsFromCacheType(CacheType cacheType)
  1145. {
  1146. switch (cacheType)
  1147. {
  1148. case CacheType_Local:
  1149. return FldInfo_FromLocal;
  1150. case CacheType_Proto:
  1151. return FldInfo_FromProto;
  1152. case CacheType_LocalWithoutProperty:
  1153. return FldInfo_FromLocalWithoutProperty;
  1154. case CacheType_Getter:
  1155. case CacheType_Setter:
  1156. return FldInfo_FromAccessor;
  1157. default:
  1158. return FldInfo_NoInfo;
  1159. }
  1160. }
  1161. FldInfoFlags DynamicProfileInfo::FldInfoFlagsFromSlotType(SlotType slotType)
  1162. {
  1163. switch (slotType)
  1164. {
  1165. case SlotType_Inline:
  1166. return FldInfo_FromInlineSlots;
  1167. case SlotType_Aux:
  1168. return FldInfo_FromAuxSlots;
  1169. default:
  1170. return FldInfo_NoInfo;
  1171. }
  1172. }
  1173. #if DBG_DUMP
  1174. void DynamicProfileInfo::DumpProfiledValue(char16 const * name, CallSiteInfo * callSiteInfo, uint count)
  1175. {
  1176. if (count != 0)
  1177. {
  1178. Output::Print(_u(" %-16s(%2d):"), name, count);
  1179. for (uint i = 0; i < count; i++)
  1180. {
  1181. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1182. Output::Print(_u("%2d:"), i);
  1183. if (!callSiteInfo[i].isPolymorphic)
  1184. {
  1185. switch (callSiteInfo[i].u.functionData.sourceId)
  1186. {
  1187. case NoSourceId:
  1188. Output::Print(_u(" ????"));
  1189. break;
  1190. case BuiltInSourceId:
  1191. Output::Print(_u(" b%03d"), callSiteInfo[i].u.functionData.functionId);
  1192. break;
  1193. case InvalidSourceId:
  1194. if (callSiteInfo[i].u.functionData.functionId == CallSiteMixed)
  1195. {
  1196. Output::Print(_u(" mix"));
  1197. }
  1198. else if (callSiteInfo[i].u.functionData.functionId == CallSiteCrossContext)
  1199. {
  1200. Output::Print(_u(" x"));
  1201. }
  1202. else if (callSiteInfo[i].u.functionData.functionId == CallSiteNonFunction)
  1203. {
  1204. Output::Print(_u(" !fn"));
  1205. }
  1206. else
  1207. {
  1208. Assert(false);
  1209. }
  1210. break;
  1211. default:
  1212. Output::Print(_u(" %4d:%4d"), callSiteInfo[i].u.functionData.sourceId, callSiteInfo[i].u.functionData.functionId);
  1213. break;
  1214. };
  1215. }
  1216. else
  1217. {
  1218. Output::Print(_u(" poly"));
  1219. for (int j = 0; j < DynamicProfileInfo::maxPolymorphicInliningSize; j++)
  1220. {
  1221. if (callSiteInfo[i].u.polymorphicCallSiteInfo->functionIds[j] != CallSiteNoInfo)
  1222. {
  1223. Output::Print(_u(" %4d:%4d"), callSiteInfo[i].u.polymorphicCallSiteInfo->sourceIds[j], callSiteInfo[i].u.polymorphicCallSiteInfo->functionIds[j]);
  1224. }
  1225. }
  1226. }
  1227. }
  1228. Output::Print(_u("\n"));
  1229. Output::Print(_u(" %-16s(%2d):"), _u("Callsite RetType"), count);
  1230. for (uint i = 0; i < count; i++)
  1231. {
  1232. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1233. Output::Print(_u("%2d:"), i);
  1234. char returnTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
  1235. callSiteInfo[i].returnType.ToString(returnTypeStr);
  1236. Output::Print(_u(" %S"), returnTypeStr);
  1237. }
  1238. Output::Print(_u("\n"));
  1239. }
  1240. }
  1241. void DynamicProfileInfo::DumpProfiledValue(char16 const * name, ArrayCallSiteInfo * arrayCallSiteInfo, uint count)
  1242. {
  1243. if (count != 0)
  1244. {
  1245. Output::Print(_u(" %-16s(%2d):"), name, count);
  1246. Output::Print(_u("\n"));
  1247. for (uint i = 0; i < count; i++)
  1248. {
  1249. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1250. Output::Print(_u("%4d:"), i);
  1251. Output::Print(_u(" Function Number: %2d, CallSite Number: %2d, IsNativeIntArray: %2d, IsNativeFloatArray: %2d"),
  1252. arrayCallSiteInfo[i].functionNumber, arrayCallSiteInfo[i].callSiteNumber, !arrayCallSiteInfo[i].isNotNativeInt, !arrayCallSiteInfo[i].isNotNativeFloat);
  1253. Output::Print(_u("\n"));
  1254. }
  1255. Output::Print(_u("\n"));
  1256. }
  1257. }
  1258. void DynamicProfileInfo::DumpProfiledValue(char16 const * name, ValueType * value, uint count)
  1259. {
  1260. if (count != 0)
  1261. {
  1262. Output::Print(_u(" %-16s(%2d):"), name, count);
  1263. for (uint i = 0; i < count; i++)
  1264. {
  1265. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1266. Output::Print(_u("%2d:"), i);
  1267. char valueStr[VALUE_TYPE_MAX_STRING_SIZE];
  1268. value[i].ToString(valueStr);
  1269. Output::Print(_u(" %S"), valueStr);
  1270. }
  1271. Output::Print(_u("\n"));
  1272. }
  1273. }
  1274. void DynamicProfileInfo::DumpProfiledValue(char16 const * name, uint * value, uint count)
  1275. {
  1276. if (count != 0)
  1277. {
  1278. Output::Print(_u(" %-16s(%2d):"), name, count);
  1279. for (uint i = 0; i < count; i++)
  1280. {
  1281. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1282. Output::Print(_u("%2d:%-4d"), i, value[i]);
  1283. }
  1284. Output::Print(_u("\n"));
  1285. }
  1286. }
  1287. char16 const * DynamicProfileInfo::GetImplicitCallFlagsString(ImplicitCallFlags flags)
  1288. {
  1289. // Mask out the dispose implicit call. We would bailout on reentrant dispose,
  1290. // but it shouldn't affect optimization
  1291. flags = (ImplicitCallFlags)(flags & ImplicitCall_All);
  1292. return flags == ImplicitCall_HasNoInfo ? _u("???") : flags == ImplicitCall_None ? _u("no") : _u("yes");
  1293. }
  1294. void DynamicProfileInfo::DumpProfiledValue(char16 const * name, ImplicitCallFlags * loopImplicitCallFlags, uint count)
  1295. {
  1296. if (count != 0)
  1297. {
  1298. Output::Print(_u(" %-16s(%2d):"), name, count);
  1299. for (uint i = 0; i < count; i++)
  1300. {
  1301. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1302. Output::Print(_u("%2d:%-4s"), i, GetImplicitCallFlagsString(loopImplicitCallFlags[i]));
  1303. }
  1304. Output::Print(_u("\n"));
  1305. }
  1306. }
  1307. bool DynamicProfileInfo::IsProfiledCallOp(OpCode op)
  1308. {
  1309. return Js::OpCodeUtil::IsProfiledCallOp(op) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(op) || Js::OpCodeUtil::IsProfiledConstructorCall(op);
  1310. }
  1311. bool DynamicProfileInfo::IsProfiledReturnTypeOp(OpCode op)
  1312. {
  1313. return Js::OpCodeUtil::IsProfiledReturnTypeCallOp(op);
  1314. }
  1315. template<class TData, class FGetValueType>
  1316. void DynamicProfileInfo::DumpProfiledValuesGroupedByValue(
  1317. const char16 *const name,
  1318. const TData *const data,
  1319. const uint count,
  1320. const FGetValueType GetValueType,
  1321. ArenaAllocator *const dynamicProfileInfoAllocator)
  1322. {
  1323. JsUtil::BaseDictionary<ValueType, bool, ArenaAllocator> uniqueValueTypes(dynamicProfileInfoAllocator);
  1324. for (uint i = 0; i < count; i++)
  1325. {
  1326. const ValueType valueType(GetValueType(data, i));
  1327. if (!valueType.IsUninitialized())
  1328. {
  1329. uniqueValueTypes.Item(valueType, false);
  1330. }
  1331. }
  1332. uniqueValueTypes.Map([&](const ValueType groupValueType, const bool)
  1333. {
  1334. bool header = true;
  1335. uint lastTempFld = (uint)-1;
  1336. for (uint i = 0; i < count; i++)
  1337. {
  1338. const ValueType valueType(GetValueType(data, i));
  1339. if (valueType == groupValueType)
  1340. {
  1341. if (lastTempFld == (uint)-1)
  1342. {
  1343. if (header)
  1344. {
  1345. char valueTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
  1346. valueType.ToString(valueTypeStr);
  1347. Output::Print(_u(" %s %S"), name, valueTypeStr);
  1348. Output::SkipToColumn(24);
  1349. Output::Print(_u(": %d"), i);
  1350. }
  1351. else
  1352. {
  1353. Output::Print(_u(", %d"), i);
  1354. }
  1355. header = false;
  1356. lastTempFld = i;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. if (lastTempFld != (uint)-1)
  1362. {
  1363. if (lastTempFld != i - 1)
  1364. {
  1365. Output::Print(_u("-%d"), i - 1);
  1366. }
  1367. lastTempFld = (uint)-1;
  1368. }
  1369. }
  1370. }
  1371. if (lastTempFld != (uint)-1 && lastTempFld != count - 1)
  1372. {
  1373. Output::Print(_u("-%d\n"), count - 1);
  1374. }
  1375. else if (!header)
  1376. {
  1377. Output::Print(_u("\n"));
  1378. }
  1379. });
  1380. }
  1381. void DynamicProfileInfo::DumpFldInfoFlags(char16 const * name, FldInfo * fldInfo, uint count, FldInfoFlags value, char16 const * valueName)
  1382. {
  1383. bool header = true;
  1384. uint lastTempFld = (uint)-1;
  1385. for (uint i = 0; i < count; i++)
  1386. {
  1387. if (fldInfo[i].flags & value)
  1388. {
  1389. if (lastTempFld == (uint)-1)
  1390. {
  1391. if (header)
  1392. {
  1393. Output::Print(_u(" %s %s"), name, valueName);
  1394. Output::SkipToColumn(24);
  1395. Output::Print(_u(": %d"), i);
  1396. }
  1397. else
  1398. {
  1399. Output::Print(_u(", %d"), i);
  1400. }
  1401. header = false;
  1402. lastTempFld = i;
  1403. }
  1404. }
  1405. else
  1406. {
  1407. if (lastTempFld != (uint)-1)
  1408. {
  1409. if (lastTempFld != i - 1)
  1410. {
  1411. Output::Print(_u("-%d"), i - 1);
  1412. }
  1413. lastTempFld = (uint)-1;
  1414. }
  1415. }
  1416. }
  1417. if (lastTempFld != (uint)-1 && lastTempFld != count - 1)
  1418. {
  1419. Output::Print(_u("-%d\n"), count - 1);
  1420. }
  1421. else if (!header)
  1422. {
  1423. Output::Print(_u("\n"));
  1424. }
  1425. }
  1426. void DynamicProfileInfo::DumpLoopInfo(FunctionBody *fbody)
  1427. {
  1428. if (fbody->DoJITLoopBody())
  1429. {
  1430. uint count = fbody->GetLoopCount();
  1431. Output::Print(_u(" %-16s(%2d):"), _u("Loops"), count);
  1432. for (uint i = 0; i < count; i++)
  1433. {
  1434. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1435. Output::Print(_u("%2d:%-4d"), i, fbody->GetLoopHeader(i)->interpretCount);
  1436. }
  1437. Output::Print(_u("\n"));
  1438. Output::Print(_u(" %-16s(%2d):"), _u("Loops JIT"), count);
  1439. for (uint i = 0; i < count; i++)
  1440. {
  1441. Output::Print(i != 0 && (i % 10) == 0 ? _u("\n ") : _u(" "));
  1442. Output::Print(_u("%2d:%-4d"), i, fbody->GetLoopHeader(i)->nativeCount);
  1443. }
  1444. Output::Print(_u("\n"));
  1445. }
  1446. }
  1447. void DynamicProfileInfo::Dump(FunctionBody* functionBody, ArenaAllocator * dynamicProfileInfoAllocator)
  1448. {
  1449. functionBody->DumpFunctionId(true);
  1450. Js::ArgSlot paramcount = functionBody->GetProfiledInParamsCount();
  1451. Output::Print(_u(": %-20s Interpreted:%6d, Param:%2d, ImpCall:%s, Callsite:%3d, ReturnType:%3d, LdElem:%3d, StElem:%3d, Fld%3d\n"),
  1452. functionBody->GetDisplayName(), functionBody->GetInterpretedCount(), paramcount, DynamicProfileInfo::GetImplicitCallFlagsString(this->GetImplicitCallFlags()),
  1453. functionBody->GetProfiledCallSiteCount(),
  1454. functionBody->GetProfiledReturnTypeCount(),
  1455. functionBody->GetProfiledLdElemCount(),
  1456. functionBody->GetProfiledStElemCount(),
  1457. functionBody->GetProfiledFldCount());
  1458. if (Configuration::Global.flags.Verbose)
  1459. {
  1460. DumpProfiledValue(_u("Div result type"), this->divideTypeInfo, functionBody->GetProfiledDivOrRemCount());
  1461. DumpProfiledValue(_u("Switch opt type"), this->switchTypeInfo, functionBody->GetProfiledSwitchCount());
  1462. DumpProfiledValue(_u("Param type"), this->parameterInfo, paramcount);
  1463. DumpProfiledValue(_u("Callsite"), this->callSiteInfo, functionBody->GetProfiledCallSiteCount());
  1464. DumpProfiledValue(_u("ArrayCallSite"), this->arrayCallSiteInfo, functionBody->GetProfiledArrayCallSiteCount());
  1465. DumpProfiledValue(_u("Return type"), this->returnTypeInfo, functionBody->GetProfiledReturnTypeCount());
  1466. if (dynamicProfileInfoAllocator)
  1467. {
  1468. DumpProfiledValuesGroupedByValue(
  1469. _u("Element load"),
  1470. static_cast<LdElemInfo*>(this->ldElemInfo),
  1471. this->functionBody->GetProfiledLdElemCount(),
  1472. [](const LdElemInfo *const ldElemInfo, const uint i) -> ValueType
  1473. {
  1474. return ldElemInfo[i].GetElementType();
  1475. },
  1476. dynamicProfileInfoAllocator);
  1477. DumpProfiledValuesGroupedByValue(
  1478. _u("Fld"),
  1479. static_cast<FldInfo *>(this->fldInfo),
  1480. functionBody->GetProfiledFldCount(),
  1481. [](const FldInfo *const fldInfos, const uint i) -> ValueType
  1482. {
  1483. return fldInfos[i].valueType;
  1484. },
  1485. dynamicProfileInfoAllocator);
  1486. }
  1487. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromLocal, _u("FldInfo_FromLocal"));
  1488. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromProto, _u("FldInfo_FromProto"));
  1489. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromLocalWithoutProperty, _u("FldInfo_FromLocalWithoutProperty"));
  1490. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromAccessor, _u("FldInfo_FromAccessor"));
  1491. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_Polymorphic, _u("FldInfo_Polymorphic"));
  1492. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromInlineSlots, _u("FldInfo_FromInlineSlots"));
  1493. DumpFldInfoFlags(_u("Fld"), this->fldInfo, functionBody->GetProfiledFldCount(), FldInfo_FromAuxSlots, _u("FldInfo_FromAuxSlots"));
  1494. DumpLoopInfo(functionBody);
  1495. if (DynamicProfileInfo::EnableImplicitCallFlags(functionBody))
  1496. {
  1497. DumpProfiledValue(_u("Loop Imp Call"), this->loopImplicitCallFlags, functionBody->GetLoopCount());
  1498. }
  1499. if (functionBody->GetLoopCount())
  1500. {
  1501. Output::Print(_u(" Loop Flags:\n"));
  1502. for (uint i = 0; i < functionBody->GetLoopCount(); ++i)
  1503. {
  1504. Output::Print(_u(" Loop %d:\n"), i);
  1505. LoopFlags lf = this->GetLoopFlags(i);
  1506. Output::Print(
  1507. _u(" isInterpreted : %s\n")
  1508. _u(" memopMinCountReached : %s\n"),
  1509. IsTrueOrFalse(lf.isInterpreted),
  1510. IsTrueOrFalse(lf.memopMinCountReached)
  1511. );
  1512. }
  1513. }
  1514. Output::Print(
  1515. _u(" Settings:")
  1516. _u(" disableAggressiveIntTypeSpec : %s")
  1517. _u(" disableAggressiveIntTypeSpec_jitLoopBody : %s")
  1518. _u(" disableAggressiveMulIntTypeSpec : %s")
  1519. _u(" disableAggressiveMulIntTypeSpec_jitLoopBody : %s")
  1520. _u(" disableDivIntTypeSpec : %s")
  1521. _u(" disableDivIntTypeSpec_jitLoopBody : %s")
  1522. _u(" disableLossyIntTypeSpec : %s")
  1523. _u(" disableMemOp : %s")
  1524. _u(" disableTrackIntOverflow : %s")
  1525. _u(" disableFloatTypeSpec : %s")
  1526. _u(" disableCheckThis : %s")
  1527. _u(" disableArrayCheckHoist : %s")
  1528. _u(" disableArrayCheckHoist_jitLoopBody : %s")
  1529. _u(" disableArrayMissingValueCheckHoist : %s")
  1530. _u(" disableArrayMissingValueCheckHoist_jitLoopBody : %s")
  1531. _u(" disableJsArraySegmentHoist : %s")
  1532. _u(" disableJsArraySegmentHoist_jitLoopBody : %s")
  1533. _u(" disableArrayLengthHoist : %s")
  1534. _u(" disableArrayLengthHoist_jitLoopBody : %s")
  1535. _u(" disableTypedArrayTypeSpec: %s")
  1536. _u(" disableTypedArrayTypeSpec_jitLoopBody: %s")
  1537. _u(" disableLdLenIntSpec: %s")
  1538. _u(" disableBoundCheckHoist : %s")
  1539. _u(" disableBoundCheckHoist_jitLoopBody : %s")
  1540. _u(" disableLoopCountBasedBoundCheckHoist : %s")
  1541. _u(" disableLoopCountBasedBoundCheckHoist_jitLoopBody : %s")
  1542. _u(" hasPolymorphicFldAccess : %s")
  1543. _u(" hasLdFldCallSite: %s")
  1544. _u(" disableFloorInlining: %s")
  1545. _u(" disableNoProfileBailouts: %s")
  1546. _u(" disableSwitchOpt : %s")
  1547. _u(" disableEquivalentObjTypeSpec : %s\n")
  1548. _u(" disableObjTypeSpec_jitLoopBody : %s\n")
  1549. _u(" disablePowIntTypeSpec : %s\n")
  1550. _u(" disableStackArgOpt : %s\n")
  1551. _u(" disableTagCheck : %s\n")
  1552. _u(" disableOptimizeTryFinally : %s\n"),
  1553. IsTrueOrFalse(this->bits.disableAggressiveIntTypeSpec),
  1554. IsTrueOrFalse(this->bits.disableAggressiveIntTypeSpec_jitLoopBody),
  1555. IsTrueOrFalse(this->bits.disableAggressiveMulIntTypeSpec),
  1556. IsTrueOrFalse(this->bits.disableAggressiveMulIntTypeSpec_jitLoopBody),
  1557. IsTrueOrFalse(this->bits.disableDivIntTypeSpec),
  1558. IsTrueOrFalse(this->bits.disableDivIntTypeSpec_jitLoopBody),
  1559. IsTrueOrFalse(this->bits.disableLossyIntTypeSpec),
  1560. IsTrueOrFalse(this->bits.disableMemOp),
  1561. IsTrueOrFalse(this->bits.disableTrackCompoundedIntOverflow),
  1562. IsTrueOrFalse(this->bits.disableFloatTypeSpec),
  1563. IsTrueOrFalse(this->bits.disableCheckThis),
  1564. IsTrueOrFalse(this->bits.disableArrayCheckHoist),
  1565. IsTrueOrFalse(this->bits.disableArrayCheckHoist_jitLoopBody),
  1566. IsTrueOrFalse(this->bits.disableArrayMissingValueCheckHoist),
  1567. IsTrueOrFalse(this->bits.disableArrayMissingValueCheckHoist_jitLoopBody),
  1568. IsTrueOrFalse(this->bits.disableJsArraySegmentHoist),
  1569. IsTrueOrFalse(this->bits.disableJsArraySegmentHoist_jitLoopBody),
  1570. IsTrueOrFalse(this->bits.disableArrayLengthHoist),
  1571. IsTrueOrFalse(this->bits.disableArrayLengthHoist_jitLoopBody),
  1572. IsTrueOrFalse(this->bits.disableTypedArrayTypeSpec),
  1573. IsTrueOrFalse(this->bits.disableTypedArrayTypeSpec_jitLoopBody),
  1574. IsTrueOrFalse(this->bits.disableLdLenIntSpec),
  1575. IsTrueOrFalse(this->bits.disableBoundCheckHoist),
  1576. IsTrueOrFalse(this->bits.disableBoundCheckHoist_jitLoopBody),
  1577. IsTrueOrFalse(this->bits.disableLoopCountBasedBoundCheckHoist),
  1578. IsTrueOrFalse(this->bits.disableLoopCountBasedBoundCheckHoist_jitLoopBody),
  1579. IsTrueOrFalse(this->bits.hasPolymorphicFldAccess),
  1580. IsTrueOrFalse(this->bits.hasLdFldCallSite),
  1581. IsTrueOrFalse(this->bits.disableFloorInlining),
  1582. IsTrueOrFalse(this->bits.disableNoProfileBailouts),
  1583. IsTrueOrFalse(this->bits.disableSwitchOpt),
  1584. IsTrueOrFalse(this->bits.disableEquivalentObjTypeSpec),
  1585. IsTrueOrFalse(this->bits.disableObjTypeSpec_jitLoopBody),
  1586. IsTrueOrFalse(this->bits.disablePowIntIntTypeSpec),
  1587. IsTrueOrFalse(this->bits.disableStackArgOpt),
  1588. IsTrueOrFalse(this->bits.disableTagCheck),
  1589. IsTrueOrFalse(this->bits.disableOptimizeTryFinally));
  1590. }
  1591. }
  1592. void DynamicProfileInfo::DumpList(
  1593. DynamicProfileInfoList * profileInfoList, ArenaAllocator * dynamicProfileInfoAllocator)
  1594. {
  1595. AUTO_NESTED_HANDLED_EXCEPTION_TYPE(ExceptionType_DisableCheck);
  1596. if (Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase))
  1597. {
  1598. FOREACH_SLISTBASE_ENTRY(DynamicProfileInfo * const, info, profileInfoList)
  1599. {
  1600. if (Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase, info->GetFunctionBody()->GetSourceContextId(), info->GetFunctionBody()->GetLocalFunctionId()))
  1601. {
  1602. info->Dump(info->GetFunctionBody(), dynamicProfileInfoAllocator);
  1603. }
  1604. }
  1605. NEXT_SLISTBASE_ENTRY;
  1606. }
  1607. if (Configuration::Global.flags.Dump.IsEnabled(JITLoopBodyPhase) && !Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase))
  1608. {
  1609. FOREACH_SLISTBASE_ENTRY(DynamicProfileInfo * const, info, profileInfoList)
  1610. {
  1611. if (info->functionBody->GetLoopCount() > 0)
  1612. {
  1613. info->functionBody->DumpFunctionId(true);
  1614. Output::Print(_u(": %-20s\n"), info->functionBody->GetDisplayName());
  1615. DumpLoopInfo(info->functionBody);
  1616. }
  1617. }
  1618. NEXT_SLISTBASE_ENTRY;
  1619. }
  1620. if (PHASE_STATS1(DynamicProfilePhase))
  1621. {
  1622. uint estimatedSavedBytes = sizeof(uint); // count of functions
  1623. uint functionSaved = 0;
  1624. uint loopSaved = 0;
  1625. uint callSiteSaved = 0;
  1626. uint elementAccessSaved = 0;
  1627. uint fldAccessSaved = 0;
  1628. FOREACH_SLISTBASE_ENTRY(DynamicProfileInfo * const, info, profileInfoList)
  1629. {
  1630. bool hasHotLoop = false;
  1631. if (info->functionBody->DoJITLoopBody())
  1632. {
  1633. for (uint i = 0; i < info->functionBody->GetLoopCount(); i++)
  1634. {
  1635. if (info->functionBody->GetLoopHeader(i)->interpretCount >= 10)
  1636. {
  1637. hasHotLoop = true;
  1638. break;
  1639. }
  1640. }
  1641. }
  1642. if (hasHotLoop || info->functionBody->GetInterpretedCount() >= 10)
  1643. {
  1644. functionSaved++;
  1645. loopSaved += info->functionBody->GetLoopCount();
  1646. estimatedSavedBytes += sizeof(uint) * 5; // function number, loop count, call site count, local array, temp array
  1647. estimatedSavedBytes += (info->functionBody->GetLoopCount() + 7) / 8; // hot loop bit vector
  1648. estimatedSavedBytes += (info->functionBody->GetProfiledCallSiteCount() + 7) / 8; // call site bit vector
  1649. // call site function number
  1650. for (ProfileId i = 0; i < info->functionBody->GetProfiledCallSiteCount(); i++)
  1651. {
  1652. // TODO poly
  1653. if ((info->callSiteInfo[i].u.functionData.sourceId != NoSourceId) && (info->callSiteInfo[i].u.functionData.sourceId != InvalidSourceId))
  1654. {
  1655. estimatedSavedBytes += sizeof(CallSiteInfo);
  1656. callSiteSaved++;
  1657. }
  1658. }
  1659. elementAccessSaved += info->functionBody->GetProfiledLdElemCount() + info->functionBody->GetProfiledStElemCount();
  1660. fldAccessSaved += info->functionBody->GetProfiledFldCount();
  1661. estimatedSavedBytes += (info->functionBody->GetProfiledLdElemCount() + info->functionBody->GetProfiledStElemCount() + 7) / 8; // temp array access
  1662. }
  1663. }
  1664. NEXT_SLISTBASE_ENTRY;
  1665. if (estimatedSavedBytes != sizeof(uint))
  1666. {
  1667. Output::Print(_u("Estimated save size (Memory used): %6d (%6d): %3d %3d %4d %4d %3d\n"),
  1668. estimatedSavedBytes, dynamicProfileInfoAllocator->Size(), functionSaved, loopSaved, callSiteSaved,
  1669. elementAccessSaved, fldAccessSaved);
  1670. }
  1671. }
  1672. }
  1673. void DynamicProfileInfo::DumpScriptContext(ScriptContext * scriptContext)
  1674. {
  1675. if (Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase))
  1676. {
  1677. Output::Print(_u("Sources:\n"));
  1678. if (scriptContext->GetSourceContextInfoMap() != nullptr)
  1679. {
  1680. scriptContext->GetSourceContextInfoMap()->Map([&](DWORD_PTR dwHostSourceContext, SourceContextInfo * sourceContextInfo)
  1681. {
  1682. if (sourceContextInfo->sourceContextId != Js::Constants::NoSourceContext)
  1683. {
  1684. Output::Print(_u("%2d: %s (Function count: %d)\n"), sourceContextInfo->sourceContextId, sourceContextInfo->url, sourceContextInfo->nextLocalFunctionId);
  1685. }
  1686. });
  1687. }
  1688. if (scriptContext->GetDynamicSourceContextInfoMap() != nullptr)
  1689. {
  1690. scriptContext->GetDynamicSourceContextInfoMap()->Map([&](DWORD_PTR dwHostSourceContext, SourceContextInfo * sourceContextInfo)
  1691. {
  1692. Output::Print(_u("%2d: %d (Dynamic) (Function count: %d)\n"), sourceContextInfo->sourceContextId, sourceContextInfo->hash, sourceContextInfo->nextLocalFunctionId);
  1693. });
  1694. }
  1695. }
  1696. DynamicProfileInfo::DumpList(scriptContext->GetProfileInfoList(), scriptContext->DynamicProfileInfoAllocator());
  1697. Output::Flush();
  1698. }
  1699. #endif
  1700. #ifdef DYNAMIC_PROFILE_STORAGE
  1701. #if DBG_DUMP
  1702. void BufferWriter::Log(DynamicProfileInfo* info)
  1703. {
  1704. if (Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase, info->GetFunctionBody()->GetSourceContextId(), info->GetFunctionBody()->GetLocalFunctionId()))
  1705. {
  1706. Output::Print(_u("Saving:"));
  1707. info->Dump(info->GetFunctionBody());
  1708. }
  1709. }
  1710. #endif
  1711. template <typename T>
  1712. bool DynamicProfileInfo::Serialize(T * writer)
  1713. {
  1714. #if DBG_DUMP
  1715. writer->Log(this);
  1716. #endif
  1717. FunctionBody * functionBody = this->GetFunctionBody();
  1718. Js::ArgSlot paramInfoCount = functionBody->GetProfiledInParamsCount();
  1719. if (!writer->Write(functionBody->GetLocalFunctionId())
  1720. || !writer->Write(paramInfoCount)
  1721. || !writer->WriteArray(this->parameterInfo, paramInfoCount)
  1722. || !writer->Write(functionBody->GetProfiledLdElemCount())
  1723. || !writer->WriteArray(this->ldElemInfo, functionBody->GetProfiledLdElemCount())
  1724. || !writer->Write(functionBody->GetProfiledStElemCount())
  1725. || !writer->WriteArray(this->stElemInfo, functionBody->GetProfiledStElemCount())
  1726. || !writer->Write(functionBody->GetProfiledArrayCallSiteCount())
  1727. || !writer->WriteArray(this->arrayCallSiteInfo, functionBody->GetProfiledArrayCallSiteCount())
  1728. || !writer->Write(functionBody->GetProfiledFldCount())
  1729. || !writer->WriteArray(this->fldInfo, functionBody->GetProfiledFldCount())
  1730. || !writer->Write(functionBody->GetProfiledSlotCount())
  1731. || !writer->WriteArray(this->slotInfo, functionBody->GetProfiledSlotCount())
  1732. || !writer->Write(functionBody->GetProfiledCallSiteCount())
  1733. || !writer->WriteArray(this->callSiteInfo, functionBody->GetProfiledCallSiteCount())
  1734. || !writer->Write(functionBody->GetProfiledDivOrRemCount())
  1735. || !writer->WriteArray(this->divideTypeInfo, functionBody->GetProfiledDivOrRemCount())
  1736. || !writer->Write(functionBody->GetProfiledSwitchCount())
  1737. || !writer->WriteArray(this->switchTypeInfo, functionBody->GetProfiledSwitchCount())
  1738. || !writer->Write(functionBody->GetProfiledReturnTypeCount())
  1739. || !writer->WriteArray(this->returnTypeInfo, functionBody->GetProfiledReturnTypeCount())
  1740. || !writer->Write(functionBody->GetLoopCount())
  1741. || !writer->WriteArray(this->loopImplicitCallFlags, functionBody->GetLoopCount())
  1742. || !writer->Write(this->implicitCallFlags)
  1743. || !writer->Write(this->thisInfo)
  1744. || !writer->Write(this->bits)
  1745. || !writer->Write(this->m_recursiveInlineInfo)
  1746. || (this->loopFlags && !writer->WriteArray(this->loopFlags->GetData(), this->loopFlags->WordCount())))
  1747. {
  1748. return false;
  1749. }
  1750. return true;
  1751. }
  1752. template <typename T>
  1753. DynamicProfileInfo * DynamicProfileInfo::Deserialize(T * reader, Recycler* recycler, Js::LocalFunctionId * functionId)
  1754. {
  1755. Js::ArgSlot paramInfoCount = 0;
  1756. ProfileId ldElemInfoCount = 0;
  1757. ProfileId stElemInfoCount = 0;
  1758. ProfileId arrayCallSiteCount = 0;
  1759. ProfileId slotInfoCount = 0;
  1760. ProfileId callSiteInfoCount = 0;
  1761. ProfileId returnTypeInfoCount = 0;
  1762. ProfileId divCount = 0;
  1763. ProfileId switchCount = 0;
  1764. uint fldInfoCount = 0;
  1765. uint loopCount = 0;
  1766. ValueType * paramInfo = nullptr;
  1767. LdElemInfo * ldElemInfo = nullptr;
  1768. StElemInfo * stElemInfo = nullptr;
  1769. ArrayCallSiteInfo * arrayCallSiteInfo = nullptr;
  1770. FldInfo * fldInfo = nullptr;
  1771. ValueType * slotInfo = nullptr;
  1772. CallSiteInfo * callSiteInfo = nullptr;
  1773. ValueType * divTypeInfo = nullptr;
  1774. ValueType * switchTypeInfo = nullptr;
  1775. ValueType * returnTypeInfo = nullptr;
  1776. ImplicitCallFlags * loopImplicitCallFlags = nullptr;
  1777. BVFixed * loopFlags = nullptr;
  1778. ImplicitCallFlags implicitCallFlags;
  1779. ThisInfo thisInfo;
  1780. Bits bits;
  1781. uint32 recursiveInlineInfo = 0;
  1782. try
  1783. {
  1784. AUTO_NESTED_HANDLED_EXCEPTION_TYPE(ExceptionType_OutOfMemory);
  1785. if (!reader->Read(functionId))
  1786. {
  1787. return nullptr;
  1788. }
  1789. if (!reader->Read(&paramInfoCount))
  1790. {
  1791. return nullptr;
  1792. }
  1793. if (paramInfoCount != 0)
  1794. {
  1795. paramInfo = RecyclerNewArrayLeaf(recycler, ValueType, paramInfoCount);
  1796. if (!reader->ReadArray(paramInfo, paramInfoCount))
  1797. {
  1798. goto Error;
  1799. }
  1800. }
  1801. if (!reader->Read(&ldElemInfoCount))
  1802. {
  1803. goto Error;
  1804. }
  1805. if (ldElemInfoCount != 0)
  1806. {
  1807. ldElemInfo = RecyclerNewArrayLeaf(recycler, LdElemInfo, ldElemInfoCount);
  1808. if (!reader->ReadArray(ldElemInfo, ldElemInfoCount))
  1809. {
  1810. goto Error;
  1811. }
  1812. }
  1813. if (!reader->Read(&stElemInfoCount))
  1814. {
  1815. goto Error;
  1816. }
  1817. if (stElemInfoCount != 0)
  1818. {
  1819. stElemInfo = RecyclerNewArrayLeaf(recycler, StElemInfo, stElemInfoCount);
  1820. if (!reader->ReadArray(stElemInfo, stElemInfoCount))
  1821. {
  1822. goto Error;
  1823. }
  1824. }
  1825. if (!reader->Read(&arrayCallSiteCount))
  1826. {
  1827. goto Error;
  1828. }
  1829. if (arrayCallSiteCount != 0)
  1830. {
  1831. arrayCallSiteInfo = RecyclerNewArrayLeaf(recycler, ArrayCallSiteInfo, arrayCallSiteCount);
  1832. if (!reader->ReadArray(arrayCallSiteInfo, arrayCallSiteCount))
  1833. {
  1834. goto Error;
  1835. }
  1836. }
  1837. if (!reader->Read(&fldInfoCount))
  1838. {
  1839. goto Error;
  1840. }
  1841. if (fldInfoCount != 0)
  1842. {
  1843. fldInfo = RecyclerNewArrayLeaf(recycler, FldInfo, fldInfoCount);
  1844. if (!reader->ReadArray(fldInfo, fldInfoCount))
  1845. {
  1846. goto Error;
  1847. }
  1848. }
  1849. if (!reader->Read(&slotInfoCount))
  1850. {
  1851. goto Error;
  1852. }
  1853. if (slotInfoCount != 0)
  1854. {
  1855. slotInfo = RecyclerNewArrayLeaf(recycler, ValueType, slotInfoCount);
  1856. if (!reader->ReadArray(slotInfo, slotInfoCount))
  1857. {
  1858. goto Error;
  1859. }
  1860. }
  1861. if (!reader->Read(&callSiteInfoCount))
  1862. {
  1863. goto Error;
  1864. }
  1865. if (callSiteInfoCount != 0)
  1866. {
  1867. // CallSiteInfo contains pointer "polymorphicCallSiteInfo", but
  1868. // we explicitly save that pointer in FunctionBody. Safe to
  1869. // allocate CallSiteInfo[] as Leaf here.
  1870. callSiteInfo = RecyclerNewArrayLeaf(recycler, CallSiteInfo, callSiteInfoCount);
  1871. if (!reader->ReadArray(callSiteInfo, callSiteInfoCount))
  1872. {
  1873. goto Error;
  1874. }
  1875. }
  1876. if (!reader->Read(&divCount))
  1877. {
  1878. goto Error;
  1879. }
  1880. if (divCount != 0)
  1881. {
  1882. divTypeInfo = RecyclerNewArrayLeaf(recycler, ValueType, divCount);
  1883. if (!reader->ReadArray(divTypeInfo, divCount))
  1884. {
  1885. goto Error;
  1886. }
  1887. }
  1888. if (!reader->Read(&switchCount))
  1889. {
  1890. goto Error;
  1891. }
  1892. if (switchCount != 0)
  1893. {
  1894. switchTypeInfo = RecyclerNewArrayLeaf(recycler, ValueType, switchCount);
  1895. if (!reader->ReadArray(switchTypeInfo, switchCount))
  1896. {
  1897. goto Error;
  1898. }
  1899. }
  1900. if (!reader->Read(&returnTypeInfoCount))
  1901. {
  1902. goto Error;
  1903. }
  1904. if (returnTypeInfoCount != 0)
  1905. {
  1906. returnTypeInfo = RecyclerNewArrayLeaf(recycler, ValueType, returnTypeInfoCount);
  1907. if (!reader->ReadArray(returnTypeInfo, returnTypeInfoCount))
  1908. {
  1909. goto Error;
  1910. }
  1911. }
  1912. if (!reader->Read(&loopCount))
  1913. {
  1914. goto Error;
  1915. }
  1916. if (loopCount != 0)
  1917. {
  1918. loopImplicitCallFlags = RecyclerNewArrayLeaf(recycler, ImplicitCallFlags, loopCount);
  1919. if (!reader->ReadArray(loopImplicitCallFlags, loopCount))
  1920. {
  1921. goto Error;
  1922. }
  1923. }
  1924. if (!reader->Read(&implicitCallFlags) ||
  1925. !reader->Read(&thisInfo) ||
  1926. !reader->Read(&bits) ||
  1927. !reader->Read(&recursiveInlineInfo))
  1928. {
  1929. goto Error;
  1930. }
  1931. if (loopCount != 0)
  1932. {
  1933. loopFlags = BVFixed::New(loopCount * LoopFlags::COUNT, recycler);
  1934. if (!reader->ReadArray(loopFlags->GetData(), loopFlags->WordCount()))
  1935. {
  1936. goto Error;
  1937. }
  1938. }
  1939. DynamicProfileFunctionInfo * dynamicProfileFunctionInfo = RecyclerNewStructLeaf(recycler, DynamicProfileFunctionInfo);
  1940. dynamicProfileFunctionInfo->paramInfoCount = paramInfoCount;
  1941. dynamicProfileFunctionInfo->ldElemInfoCount = ldElemInfoCount;
  1942. dynamicProfileFunctionInfo->stElemInfoCount = stElemInfoCount;
  1943. dynamicProfileFunctionInfo->arrayCallSiteCount = arrayCallSiteCount;
  1944. dynamicProfileFunctionInfo->fldInfoCount = fldInfoCount;
  1945. dynamicProfileFunctionInfo->slotInfoCount = slotInfoCount;
  1946. dynamicProfileFunctionInfo->callSiteInfoCount = callSiteInfoCount;
  1947. dynamicProfileFunctionInfo->divCount = divCount;
  1948. dynamicProfileFunctionInfo->switchCount = switchCount;
  1949. dynamicProfileFunctionInfo->returnTypeInfoCount = returnTypeInfoCount;
  1950. dynamicProfileFunctionInfo->loopCount = loopCount;
  1951. DynamicProfileInfo * dynamicProfileInfo = RecyclerNew(recycler, DynamicProfileInfo);
  1952. dynamicProfileInfo->dynamicProfileFunctionInfo = dynamicProfileFunctionInfo;
  1953. dynamicProfileInfo->parameterInfo = paramInfo;
  1954. dynamicProfileInfo->ldElemInfo = ldElemInfo;
  1955. dynamicProfileInfo->stElemInfo = stElemInfo;
  1956. dynamicProfileInfo->arrayCallSiteInfo = arrayCallSiteInfo;
  1957. dynamicProfileInfo->fldInfo = fldInfo;
  1958. dynamicProfileInfo->slotInfo = slotInfo;
  1959. dynamicProfileInfo->callSiteInfo = callSiteInfo;
  1960. dynamicProfileInfo->divideTypeInfo = divTypeInfo;
  1961. dynamicProfileInfo->switchTypeInfo = switchTypeInfo;
  1962. dynamicProfileInfo->returnTypeInfo = returnTypeInfo;
  1963. dynamicProfileInfo->loopImplicitCallFlags = loopImplicitCallFlags;
  1964. dynamicProfileInfo->implicitCallFlags = implicitCallFlags;
  1965. dynamicProfileInfo->loopFlags = loopFlags;
  1966. dynamicProfileInfo->thisInfo = thisInfo;
  1967. dynamicProfileInfo->bits = bits;
  1968. dynamicProfileInfo->m_recursiveInlineInfo = recursiveInlineInfo;
  1969. // Fixed functions and object type data is not serialized. There is no point in trying to serialize polymorphic call site info.
  1970. dynamicProfileInfo->ResetAllPolymorphicCallSiteInfo();
  1971. return dynamicProfileInfo;
  1972. }
  1973. catch (OutOfMemoryException)
  1974. {
  1975. }
  1976. Error:
  1977. return nullptr;
  1978. }
  1979. // Explicit instantiations - to force the compiler to generate these - so they can be referenced from other compilation units.
  1980. template DynamicProfileInfo * DynamicProfileInfo::Deserialize<BufferReader>(BufferReader*, Recycler*, Js::LocalFunctionId *);
  1981. template bool DynamicProfileInfo::Serialize<BufferSizeCounter>(BufferSizeCounter*);
  1982. template bool DynamicProfileInfo::Serialize<BufferWriter>(BufferWriter*);
  1983. void DynamicProfileInfo::UpdateSourceDynamicProfileManagers(ScriptContext * scriptContext)
  1984. {
  1985. // We don't clear old dynamic data here, because if a function is inlined, it will never go through the
  1986. // EnsureDynamicProfileThunk and thus not appear in the list. We would want to keep those data as well.
  1987. // Just save/update the data from function that has execute.
  1988. // That means that the data will never go away, probably not a good policy if this is cached for web page in WININET.
  1989. DynamicProfileInfoList * profileInfoList = scriptContext->GetProfileInfoList();
  1990. FOREACH_SLISTBASE_ENTRY(DynamicProfileInfo * const, info, profileInfoList)
  1991. {
  1992. FunctionBody * functionBody = info->GetFunctionBody();
  1993. SourceDynamicProfileManager * sourceDynamicProfileManager = functionBody->GetSourceContextInfo()->sourceDynamicProfileManager;
  1994. sourceDynamicProfileManager->SaveDynamicProfileInfo(functionBody->GetLocalFunctionId(), info);
  1995. }
  1996. NEXT_SLISTBASE_ENTRY
  1997. }
  1998. #endif
  1999. #ifdef RUNTIME_DATA_COLLECTION
  2000. CriticalSection DynamicProfileInfo::s_csOutput;
  2001. template <typename T>
  2002. void DynamicProfileInfo::WriteData(const T& data, FILE * file)
  2003. {
  2004. fwrite(&data, sizeof(T), 1, file);
  2005. }
  2006. template <>
  2007. void DynamicProfileInfo::WriteData<char16 const *>(char16 const * const& sz, FILE * file)
  2008. {
  2009. if (sz)
  2010. {
  2011. charcount_t len = static_cast<charcount_t>(wcslen(sz));
  2012. utf8char_t * tempBuffer = HeapNewArray(utf8char_t, len * 3);
  2013. size_t cbNeeded = utf8::EncodeInto(tempBuffer, sz, len);
  2014. fwrite(&cbNeeded, sizeof(cbNeeded), 1, file);
  2015. fwrite(tempBuffer, sizeof(utf8char_t), cbNeeded, file);
  2016. HeapDeleteArray(len * 3, tempBuffer);
  2017. }
  2018. else
  2019. {
  2020. charcount_t len = 0;
  2021. fwrite(&len, sizeof(len), 1, file);
  2022. }
  2023. }
  2024. template <typename T>
  2025. void DynamicProfileInfo::WriteArray(uint count, T * arr, FILE * file)
  2026. {
  2027. WriteData(count, file);
  2028. for (uint i = 0; i < count; i++)
  2029. {
  2030. WriteData(arr[i], file);
  2031. }
  2032. }
  2033. template <typename T>
  2034. void DynamicProfileInfo::WriteArray(uint count, WriteBarrierPtr<T> arr, FILE * file)
  2035. {
  2036. WriteArray(count, static_cast<T*>(arr), file);
  2037. }
  2038. template <>
  2039. void DynamicProfileInfo::WriteData<FunctionBody *>(FunctionBody * const& functionBody, FILE * file)
  2040. {
  2041. WriteData(functionBody->GetSourceContextInfo()->sourceContextId, file);
  2042. WriteData(functionBody->GetLocalFunctionId(), file);
  2043. }
  2044. void DynamicProfileInfo::DumpScriptContextToFile(ScriptContext * scriptContext)
  2045. {
  2046. if (Configuration::Global.flags.RuntimeDataOutputFile == nullptr)
  2047. {
  2048. return;
  2049. }
  2050. AutoCriticalSection autocs(&s_csOutput);
  2051. FILE * file;
  2052. if (_wfopen_s(&file, Configuration::Global.flags.RuntimeDataOutputFile, _u("ab+")) != 0 || file == nullptr)
  2053. {
  2054. return;
  2055. }
  2056. WriteData(scriptContext->GetAllocId(), file);
  2057. WriteData(scriptContext->GetCreateTime(), file);
  2058. WriteData(scriptContext->GetUrl(), file);
  2059. WriteData(scriptContext->GetSourceContextInfoMap() != nullptr ? scriptContext->GetSourceContextInfoMap()->Count() : 0, file);
  2060. if (scriptContext->GetSourceContextInfoMap())
  2061. {
  2062. scriptContext->GetSourceContextInfoMap()->Map([&](DWORD_PTR dwHostSourceContext, SourceContextInfo * sourceContextInfo)
  2063. {
  2064. WriteData(sourceContextInfo->sourceContextId, file);
  2065. WriteData(sourceContextInfo->nextLocalFunctionId, file);
  2066. WriteData(sourceContextInfo->url, file);
  2067. });
  2068. }
  2069. FOREACH_SLISTBASE_ENTRY(DynamicProfileInfo * const, info, scriptContext->GetProfileInfoList())
  2070. {
  2071. WriteData((byte)1, file);
  2072. WriteData(info->functionBody, file);
  2073. WriteData(info->functionBody->GetDisplayName(), file);
  2074. WriteData(info->functionBody->GetInterpretedCount(), file);
  2075. uint loopCount = info->functionBody->GetLoopCount();
  2076. WriteData(loopCount, file);
  2077. for (uint i = 0; i < loopCount; i++)
  2078. {
  2079. if (info->functionBody->DoJITLoopBody())
  2080. {
  2081. WriteData(info->functionBody->GetLoopHeader(i)->interpretCount, file);
  2082. }
  2083. else
  2084. {
  2085. WriteData(-1, file);
  2086. }
  2087. }
  2088. WriteArray(info->functionBody->GetProfiledLdElemCount(), info->ldElemInfo, file);
  2089. WriteArray(info->functionBody->GetProfiledStElemCount(), info->stElemInfo, file);
  2090. WriteArray(info->functionBody->GetProfiledArrayCallSiteCount(), info->arrayCallSiteInfo, file);
  2091. WriteArray(info->functionBody->GetProfiledCallSiteCount(), info->callSiteInfo, file);
  2092. }
  2093. NEXT_SLISTBASE_ENTRY;
  2094. WriteData((byte)0, file);
  2095. fflush(file);
  2096. fclose(file);
  2097. }
  2098. #endif
  2099. void DynamicProfileInfo::InstantiateForceInlinedMembers()
  2100. {
  2101. // Force-inlined functions defined in a translation unit need a reference from an extern non-force-inlined function in the
  2102. // same translation unit to force an instantiation of the force-inlined function. Otherwise, if the force-inlined function
  2103. // is not referenced in the same translation unit, it will not be generated and the linker is not able to find the
  2104. // definition to inline the function in other translation units.
  2105. Assert(false);
  2106. FunctionBody *const functionBody = nullptr;
  2107. const Js::Var var = nullptr;
  2108. DynamicProfileInfo *const p = nullptr;
  2109. p->RecordFieldAccess(functionBody, 0, var, FldInfo_NoInfo);
  2110. p->RecordDivideResultType(functionBody, 0, var);
  2111. p->RecordModulusOpType(functionBody, 0, false);
  2112. p->RecordSwitchType(functionBody, 0, var);
  2113. p->RecordPolymorphicFieldAccess(functionBody, 0);
  2114. p->RecordSlotLoad(functionBody, 0, var);
  2115. p->RecordParameterInfo(functionBody, 0, var);
  2116. p->RecordReturnTypeOnCallSiteInfo(functionBody, 0, var);
  2117. p->RecordReturnType(functionBody, 0, var);
  2118. p->RecordThisInfo(var, ThisType_Unknown);
  2119. }
  2120. };
  2121. bool IR::IsTypeCheckBailOutKind(IR::BailOutKind kind)
  2122. {
  2123. IR::BailOutKind kindWithoutBits = kind & ~IR::BailOutKindBits;
  2124. return
  2125. kindWithoutBits == IR::BailOutFailedTypeCheck ||
  2126. kindWithoutBits == IR::BailOutFailedFixedFieldTypeCheck ||
  2127. kindWithoutBits == IR::BailOutFailedEquivalentTypeCheck ||
  2128. kindWithoutBits == IR::BailOutFailedEquivalentFixedFieldTypeCheck;
  2129. }
  2130. bool IR::IsEquivalentTypeCheckBailOutKind(IR::BailOutKind kind)
  2131. {
  2132. IR::BailOutKind kindWithoutBits = kind & ~IR::BailOutKindBits;
  2133. return
  2134. kindWithoutBits == IR::BailOutFailedEquivalentTypeCheck ||
  2135. kindWithoutBits == IR::BailOutFailedEquivalentFixedFieldTypeCheck;
  2136. }
  2137. IR::BailOutKind IR::EquivalentToMonoTypeCheckBailOutKind(IR::BailOutKind kind)
  2138. {
  2139. switch (kind & ~IR::BailOutKindBits)
  2140. {
  2141. case IR::BailOutFailedEquivalentTypeCheck:
  2142. return IR::BailOutFailedTypeCheck | (kind & IR::BailOutKindBits);
  2143. case IR::BailOutFailedEquivalentFixedFieldTypeCheck:
  2144. return IR::BailOutFailedFixedFieldTypeCheck | (kind & IR::BailOutKindBits);
  2145. default:
  2146. Assert(0);
  2147. return IR::BailOutInvalid;
  2148. }
  2149. }
  2150. #if ENABLE_DEBUG_CONFIG_OPTIONS || defined(REJIT_STATS)
  2151. const char *const BailOutKindNames[] =
  2152. {
  2153. #define BAIL_OUT_KIND_LAST(n) "" STRINGIZE(n) ""
  2154. #define BAIL_OUT_KIND(n, ...) BAIL_OUT_KIND_LAST(n),
  2155. #define BAIL_OUT_KIND_VALUE_LAST(n, v) BAIL_OUT_KIND_LAST(n)
  2156. #define BAIL_OUT_KIND_VALUE(n, v) BAIL_OUT_KIND(n)
  2157. #include "BailOutKind.h"
  2158. #undef BAIL_OUT_KIND_LAST
  2159. };
  2160. IR::BailOutKind const BailOutKindValidBits[] =
  2161. {
  2162. #define BAIL_OUT_KIND(n, bits) (IR::BailOutKind)bits,
  2163. #define BAIL_OUT_KIND_VALUE_LAST(n, v)
  2164. #define BAIL_OUT_KIND_VALUE(n, v)
  2165. #include "BailOutKind.h"
  2166. };
  2167. bool IsValidBailOutKindAndBits(IR::BailOutKind bailOutKind)
  2168. {
  2169. IR::BailOutKind kindNoBits = bailOutKind & ~IR::BailOutKindBits;
  2170. if (kindNoBits >= IR::BailOutKindBitsStart)
  2171. {
  2172. return false;
  2173. }
  2174. return ((bailOutKind & IR::BailOutKindBits) & ~BailOutKindValidBits[kindNoBits]) == 0;
  2175. }
  2176. // Concats into the buffer, specified by the name parameter, the name of 'bit' bailout kind, specified by the enumEntryOffsetFromBitsStart parameter.
  2177. // Returns the number of bytes printed to the buffer.
  2178. size_t ConcatBailOutKindBits(_Out_writes_bytes_(dstSizeBytes) char* dst, _In_ size_t dstSizeBytes, _In_ size_t position, _In_ uint enumEntryOffsetFromBitsStart)
  2179. {
  2180. const char* kindName = BailOutKindNames[IR::BailOutKindBitsStart + static_cast<IR::BailOutKind>(enumEntryOffsetFromBitsStart)];
  2181. int printedBytes =
  2182. sprintf_s(
  2183. &dst[position],
  2184. dstSizeBytes - position * sizeof(dst[0]),
  2185. position == 0 ? "%s" : " | %s",
  2186. kindName);
  2187. return printedBytes;
  2188. }
  2189. const char* GetBailOutKindName(IR::BailOutKind kind)
  2190. {
  2191. using namespace IR;
  2192. if (!(kind & BailOutKindBits))
  2193. {
  2194. return BailOutKindNames[kind];
  2195. }
  2196. static char name[512];
  2197. size_t position = 0;
  2198. const auto normalKind = kind & ~BailOutKindBits;
  2199. if (normalKind != 0)
  2200. {
  2201. kind -= normalKind;
  2202. position +=
  2203. sprintf_s(
  2204. &name[position],
  2205. sizeof(name) / sizeof(name[0]) - position * sizeof(name[0]),
  2206. position == 0 ? "%s" : " | %s",
  2207. BailOutKindNames[normalKind]);
  2208. }
  2209. uint offset = 1;
  2210. if (kind & BailOutOnOverflow)
  2211. {
  2212. kind ^= BailOutOnOverflow;
  2213. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2214. }
  2215. ++offset;
  2216. if (kind & BailOutOnMulOverflow)
  2217. {
  2218. kind ^= BailOutOnMulOverflow;
  2219. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2220. }
  2221. ++offset;
  2222. if (kind & BailOutOnNegativeZero)
  2223. {
  2224. kind ^= BailOutOnNegativeZero;
  2225. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2226. }
  2227. ++offset;
  2228. if (kind & BailOutOnPowIntIntOverflow)
  2229. {
  2230. kind ^= BailOutOnPowIntIntOverflow;
  2231. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2232. }
  2233. ++offset;
  2234. // BailOutOnResultConditions
  2235. ++offset;
  2236. if (kind & BailOutOnMissingValue)
  2237. {
  2238. kind ^= BailOutOnMissingValue;
  2239. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2240. }
  2241. ++offset;
  2242. if (kind & BailOutConventionalNativeArrayAccessOnly)
  2243. {
  2244. kind ^= BailOutConventionalNativeArrayAccessOnly;
  2245. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2246. }
  2247. ++offset;
  2248. if (kind & BailOutConvertedNativeArray)
  2249. {
  2250. kind ^= BailOutConvertedNativeArray;
  2251. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2252. }
  2253. ++offset;
  2254. if (kind & BailOutOnArrayAccessHelperCall)
  2255. {
  2256. kind ^= BailOutOnArrayAccessHelperCall;
  2257. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2258. }
  2259. ++offset;
  2260. if (kind & BailOutOnInvalidatedArrayHeadSegment)
  2261. {
  2262. kind ^= BailOutOnInvalidatedArrayHeadSegment;
  2263. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2264. }
  2265. ++offset;
  2266. if (kind & BailOutOnInvalidatedArrayLength)
  2267. {
  2268. kind ^= BailOutOnInvalidatedArrayLength;
  2269. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2270. }
  2271. ++offset;
  2272. if (kind & BailOnStackArgsOutOfActualsRange)
  2273. {
  2274. kind ^= BailOnStackArgsOutOfActualsRange;
  2275. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2276. }
  2277. ++offset;
  2278. // BailOutForArrayBits
  2279. ++offset;
  2280. if (kind & BailOutForceByFlag)
  2281. {
  2282. kind ^= BailOutForceByFlag;
  2283. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2284. }
  2285. ++offset;
  2286. if (kind & BailOutBreakPointInFunction)
  2287. {
  2288. kind ^= BailOutBreakPointInFunction;
  2289. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2290. }
  2291. ++offset;
  2292. if (kind & BailOutStackFrameBase)
  2293. {
  2294. kind ^= BailOutStackFrameBase;
  2295. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2296. }
  2297. ++offset;
  2298. if (kind & BailOutLocalValueChanged)
  2299. {
  2300. kind ^= BailOutLocalValueChanged;
  2301. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2302. }
  2303. ++offset;
  2304. if (kind & BailOutExplicit)
  2305. {
  2306. kind ^= BailOutExplicit;
  2307. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2308. }
  2309. ++offset;
  2310. if (kind & BailOutStep)
  2311. {
  2312. kind ^= BailOutStep;
  2313. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2314. }
  2315. ++offset;
  2316. if (kind & BailOutIgnoreException)
  2317. {
  2318. kind ^= BailOutIgnoreException;
  2319. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2320. }
  2321. ++offset;
  2322. // BailOutForDebuggerBits
  2323. ++offset;
  2324. if (kind & BailOutOnDivByZero)
  2325. {
  2326. kind ^= BailOutOnDivByZero;
  2327. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2328. }
  2329. ++offset;
  2330. if (kind & BailOutOnDivOfMinInt)
  2331. {
  2332. kind ^= BailOutOnDivOfMinInt;
  2333. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2334. }
  2335. ++offset;
  2336. // BailOutOnDivSrcConditions
  2337. ++offset;
  2338. if (kind & BailOutMarkTempObject)
  2339. {
  2340. kind ^= BailOutMarkTempObject;
  2341. position += ConcatBailOutKindBits(name, sizeof(name), position, offset);
  2342. }
  2343. ++offset;
  2344. // BailOutKindBits
  2345. Assert(position != 0);
  2346. Assert(!kind);
  2347. return name;
  2348. }
  2349. #endif
  2350. #endif