ProfilingHelpers.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  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. namespace Js
  7. {
  8. #if ENABLE_PROFILE_INFO
  9. Var ProfilingHelpers::ProfiledLdElem(
  10. const Var base,
  11. const Var varIndex,
  12. FunctionBody *const functionBody,
  13. const ProfileId profileId)
  14. {
  15. Assert(base);
  16. Assert(varIndex);
  17. Assert(functionBody);
  18. Assert(profileId != Constants::NoProfileId);
  19. LdElemInfo ldElemInfo;
  20. // Only enable fast path if the javascript array is not cross site
  21. #if ENABLE_COPYONACCESS_ARRAY
  22. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(base);
  23. #endif
  24. const bool isJsArray = !TaggedNumber::Is(base) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(base);
  25. const bool fastPath = isJsArray;
  26. if(fastPath)
  27. {
  28. JavascriptArray *const array = JavascriptArray::FromVar(base);
  29. ldElemInfo.arrayType = ValueType::FromArray(ObjectType::Array, array, TypeIds_Array).ToLikely();
  30. const Var element = ProfiledLdElem_FastPath(array, varIndex, functionBody->GetScriptContext(), &ldElemInfo);
  31. ldElemInfo.elemType = ldElemInfo.elemType.Merge(element);
  32. functionBody->GetDynamicProfileInfo()->RecordElementLoad(functionBody, profileId, ldElemInfo);
  33. return element;
  34. }
  35. Assert(!isJsArray);
  36. bool isObjectWithArray;
  37. TypeId arrayTypeId;
  38. JavascriptArray *const array =
  39. JavascriptArray::GetArrayForArrayOrObjectWithArray(base, &isObjectWithArray, &arrayTypeId);
  40. do // while(false)
  41. {
  42. // The fast path is only for JavascriptArray and doesn't cover native arrays, objects with internal arrays, or typed
  43. // arrays, but we still need to profile the array
  44. uint32 headSegmentLength;
  45. if(array)
  46. {
  47. ldElemInfo.arrayType =
  48. (
  49. isObjectWithArray
  50. ? ValueType::FromObjectArray(array)
  51. : ValueType::FromArray(ObjectType::Array, array, arrayTypeId)
  52. ).ToLikely();
  53. SparseArraySegmentBase *const head = array->GetHead();
  54. Assert(head->left == 0);
  55. headSegmentLength = head->length;
  56. }
  57. else if(TypedArrayBase::TryGetLengthForOptimizedTypedArray(base, &headSegmentLength, &arrayTypeId))
  58. {
  59. bool isVirtual = (VirtualTableInfoBase::GetVirtualTable(base) == ValueType::GetVirtualTypedArrayVtable(arrayTypeId));
  60. ldElemInfo.arrayType = ValueType::FromTypeId(arrayTypeId, isVirtual).ToLikely();
  61. }
  62. else
  63. {
  64. break;
  65. }
  66. if(!TaggedInt::Is(varIndex))
  67. {
  68. ldElemInfo.neededHelperCall = true;
  69. break;
  70. }
  71. const int32 index = TaggedInt::ToInt32(varIndex);
  72. const uint32 offset = index;
  73. if(index < 0 || offset >= headSegmentLength || (array && array->IsMissingHeadSegmentItem(offset)))
  74. {
  75. ldElemInfo.neededHelperCall = true;
  76. break;
  77. }
  78. } while(false);
  79. const Var element = JavascriptOperators::OP_GetElementI(base, varIndex, functionBody->GetScriptContext());
  80. const ValueType arrayType(ldElemInfo.GetArrayType());
  81. if(!arrayType.IsUninitialized())
  82. {
  83. if(arrayType.IsLikelyObject() && arrayType.GetObjectType() == ObjectType::Array && !arrayType.HasIntElements())
  84. {
  85. JavascriptOperators::UpdateNativeArrayProfileInfoToCreateVarArray(
  86. array,
  87. arrayType.HasFloatElements(),
  88. arrayType.HasVarElements());
  89. }
  90. ldElemInfo.elemType = ValueType::Uninitialized.Merge(element);
  91. functionBody->GetDynamicProfileInfo()->RecordElementLoad(functionBody, profileId, ldElemInfo);
  92. return element;
  93. }
  94. functionBody->GetDynamicProfileInfo()->RecordElementLoadAsProfiled(functionBody, profileId);
  95. return element;
  96. }
  97. Var ProfilingHelpers::ProfiledLdElem_FastPath(
  98. JavascriptArray *const array,
  99. const Var varIndex,
  100. ScriptContext *const scriptContext,
  101. LdElemInfo *const ldElemInfo)
  102. {
  103. Assert(array);
  104. Assert(varIndex);
  105. Assert(scriptContext);
  106. do // while(false)
  107. {
  108. Assert(!array->IsCrossSiteObject());
  109. if (!TaggedInt::Is(varIndex))
  110. {
  111. break;
  112. }
  113. int32 index = TaggedInt::ToInt32(varIndex);
  114. if (index < 0)
  115. {
  116. break;
  117. }
  118. if(ldElemInfo)
  119. {
  120. SparseArraySegment<Var> *const head = static_cast<SparseArraySegment<Var> *>(array->GetHead());
  121. Assert(head->left == 0);
  122. const uint32 offset = index;
  123. if(offset < head->length)
  124. {
  125. const Var element = head->elements[offset];
  126. if(!SparseArraySegment<Var>::IsMissingItem(&element))
  127. {
  128. // Successful fastpath
  129. return element;
  130. }
  131. }
  132. ldElemInfo->neededHelperCall = true;
  133. }
  134. SparseArraySegment<Var> *seg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
  135. if ((uint32) index < seg->left)
  136. {
  137. break;
  138. }
  139. uint32 index2 = index - seg->left;
  140. if (index2 < seg->length)
  141. {
  142. Var elem = seg->elements[index2];
  143. if (elem != SparseArraySegment<Var>::GetMissingItem())
  144. {
  145. // Successful fastpath
  146. return elem;
  147. }
  148. }
  149. } while(false);
  150. if(ldElemInfo)
  151. {
  152. ldElemInfo->neededHelperCall = true;
  153. }
  154. return JavascriptOperators::OP_GetElementI(array, varIndex, scriptContext);
  155. }
  156. void ProfilingHelpers::ProfiledStElem_DefaultFlags(
  157. const Var base,
  158. const Var varIndex,
  159. const Var value,
  160. FunctionBody *const functionBody,
  161. const ProfileId profileId)
  162. {
  163. ProfiledStElem(base, varIndex, value, functionBody, profileId, PropertyOperation_None);
  164. }
  165. void ProfilingHelpers::ProfiledStElem(
  166. const Var base,
  167. const Var varIndex,
  168. const Var value,
  169. FunctionBody *const functionBody,
  170. const ProfileId profileId,
  171. const PropertyOperationFlags flags)
  172. {
  173. Assert(base);
  174. Assert(varIndex);
  175. Assert(value);
  176. Assert(functionBody);
  177. Assert(profileId != Constants::NoProfileId);
  178. StElemInfo stElemInfo;
  179. // Only enable fast path if the javascript array is not cross site
  180. const bool isJsArray = !TaggedNumber::Is(base) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(base);
  181. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  182. const bool fastPath = isJsArray && !JavascriptOperators::SetElementMayHaveImplicitCalls(scriptContext);
  183. if(fastPath)
  184. {
  185. JavascriptArray *const array = JavascriptArray::FromVar(base);
  186. stElemInfo.arrayType = ValueType::FromArray(ObjectType::Array, array, TypeIds_Array).ToLikely();
  187. stElemInfo.createdMissingValue = array->HasNoMissingValues();
  188. ProfiledStElem_FastPath(array, varIndex, value, scriptContext, flags, &stElemInfo);
  189. stElemInfo.createdMissingValue &= !array->HasNoMissingValues();
  190. functionBody->GetDynamicProfileInfo()->RecordElementStore(functionBody, profileId, stElemInfo);
  191. return;
  192. }
  193. JavascriptArray *array;
  194. bool isObjectWithArray;
  195. TypeId arrayTypeId;
  196. if(isJsArray)
  197. {
  198. array = JavascriptArray::FromVar(base);
  199. isObjectWithArray = false;
  200. arrayTypeId = TypeIds_Array;
  201. }
  202. else
  203. {
  204. array = JavascriptArray::GetArrayForArrayOrObjectWithArray(base, &isObjectWithArray, &arrayTypeId);
  205. }
  206. #if ENABLE_COPYONACCESS_ARRAY
  207. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(base);
  208. #endif
  209. do // while(false)
  210. {
  211. // The fast path is only for JavascriptArray and doesn't cover native arrays, objects with internal arrays, or typed
  212. // arrays, but we still need to profile the array
  213. uint32 length;
  214. uint32 headSegmentLength;
  215. if(array)
  216. {
  217. stElemInfo.arrayType =
  218. (
  219. isObjectWithArray
  220. ? ValueType::FromObjectArray(array)
  221. : ValueType::FromArray(ObjectType::Array, array, arrayTypeId)
  222. ).ToLikely();
  223. stElemInfo.createdMissingValue = array->HasNoMissingValues();
  224. length = array->GetLength();
  225. SparseArraySegmentBase *const head = array->GetHead();
  226. Assert(head->left == 0);
  227. headSegmentLength = head->length;
  228. }
  229. else if(TypedArrayBase::TryGetLengthForOptimizedTypedArray(base, &headSegmentLength, &arrayTypeId))
  230. {
  231. length = headSegmentLength;
  232. bool isVirtual = (VirtualTableInfoBase::GetVirtualTable(base) == ValueType::GetVirtualTypedArrayVtable(arrayTypeId));
  233. stElemInfo.arrayType = ValueType::FromTypeId(arrayTypeId, isVirtual).ToLikely();
  234. }
  235. else
  236. {
  237. break;
  238. }
  239. if(!TaggedInt::Is(varIndex))
  240. {
  241. stElemInfo.neededHelperCall = true;
  242. break;
  243. }
  244. const int32 index = TaggedInt::ToInt32(varIndex);
  245. if(index < 0)
  246. {
  247. stElemInfo.neededHelperCall = true;
  248. break;
  249. }
  250. const uint32 offset = index;
  251. if(offset >= headSegmentLength)
  252. {
  253. stElemInfo.storedOutsideHeadSegmentBounds = true;
  254. if(!isObjectWithArray && offset >= length)
  255. {
  256. stElemInfo.storedOutsideArrayBounds = true;
  257. }
  258. break;
  259. }
  260. if(array && array->IsMissingHeadSegmentItem(offset))
  261. {
  262. stElemInfo.filledMissingValue = true;
  263. }
  264. } while(false);
  265. JavascriptOperators::OP_SetElementI(base, varIndex, value, scriptContext, flags);
  266. if(!stElemInfo.GetArrayType().IsUninitialized())
  267. {
  268. if(array)
  269. {
  270. stElemInfo.createdMissingValue &= !array->HasNoMissingValues();
  271. }
  272. functionBody->GetDynamicProfileInfo()->RecordElementStore(functionBody, profileId, stElemInfo);
  273. return;
  274. }
  275. functionBody->GetDynamicProfileInfo()->RecordElementStoreAsProfiled(functionBody, profileId);
  276. }
  277. void ProfilingHelpers::ProfiledStElem_FastPath(
  278. JavascriptArray *const array,
  279. const Var varIndex,
  280. const Var value,
  281. ScriptContext *const scriptContext,
  282. const PropertyOperationFlags flags,
  283. StElemInfo *const stElemInfo)
  284. {
  285. Assert(array);
  286. Assert(varIndex);
  287. Assert(value);
  288. Assert(scriptContext);
  289. Assert(!JavascriptOperators::SetElementMayHaveImplicitCalls(scriptContext));
  290. do // while(false)
  291. {
  292. if (!TaggedInt::Is(varIndex))
  293. {
  294. break;
  295. }
  296. int32 index = TaggedInt::ToInt32(varIndex);
  297. if (index < 0)
  298. {
  299. break;
  300. }
  301. if(stElemInfo)
  302. {
  303. SparseArraySegmentBase *const head = array->GetHead();
  304. Assert(head->left == 0);
  305. const uint32 offset = index;
  306. if(offset >= head->length)
  307. {
  308. stElemInfo->storedOutsideHeadSegmentBounds = true;
  309. if(offset >= array->GetLength())
  310. {
  311. stElemInfo->storedOutsideArrayBounds = true;
  312. }
  313. }
  314. if(offset < head->size)
  315. {
  316. array->DirectProfiledSetItemInHeadSegmentAt(offset, value, stElemInfo);
  317. return;
  318. }
  319. }
  320. SparseArraySegment<Var>* lastUsedSeg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
  321. if (lastUsedSeg == NULL ||
  322. (uint32) index < lastUsedSeg->left)
  323. {
  324. break;
  325. }
  326. uint32 index2 = index - lastUsedSeg->left;
  327. if (index2 < lastUsedSeg->size)
  328. {
  329. // Successful fastpath
  330. array->DirectSetItemInLastUsedSegmentAt(index2, value);
  331. return;
  332. }
  333. } while(false);
  334. if(stElemInfo)
  335. {
  336. stElemInfo->neededHelperCall = true;
  337. }
  338. JavascriptOperators::OP_SetElementI(array, varIndex, value, scriptContext, flags);
  339. }
  340. JavascriptArray *ProfilingHelpers::ProfiledNewScArray(
  341. const uint length,
  342. FunctionBody *const functionBody,
  343. const ProfileId profileId)
  344. {
  345. Assert(functionBody);
  346. Assert(profileId != Constants::NoProfileId);
  347. // Not creating native array here if the function is unoptimized, because it turns out to be tricky to
  348. // get the initialization right if GlobOpt doesn't give us bailout. It's possible, but we should see
  349. // a use case before spending time on it.
  350. ArrayCallSiteInfo *const arrayInfo =
  351. functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
  352. Assert(arrayInfo);
  353. if (length > SparseArraySegmentBase::INLINE_CHUNK_SIZE || (functionBody->GetHasTry() && PHASE_OFF((Js::OptimizeTryCatchPhase), functionBody)))
  354. {
  355. arrayInfo->SetIsNotNativeArray();
  356. }
  357. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  358. JavascriptArray *array;
  359. if (arrayInfo->IsNativeIntArray())
  360. {
  361. JavascriptNativeIntArray *const intArray = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(length);
  362. Recycler *recycler = scriptContext->GetRecycler();
  363. intArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  364. array = intArray;
  365. }
  366. else if (arrayInfo->IsNativeFloatArray())
  367. {
  368. JavascriptNativeFloatArray *const floatArray = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(length);
  369. Recycler *recycler = scriptContext->GetRecycler();
  370. floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  371. array = floatArray;
  372. }
  373. else
  374. {
  375. array = scriptContext->GetLibrary()->CreateArrayLiteral(length);
  376. }
  377. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  378. array->CheckForceES5Array();
  379. #endif
  380. return array;
  381. }
  382. Var ProfilingHelpers::ProfiledNewScObjArray_Jit(
  383. const Var callee,
  384. void *const framePointer,
  385. const ProfileId profileId,
  386. const ProfileId arrayProfileId,
  387. CallInfo callInfo,
  388. ...)
  389. {
  390. ARGUMENTS(args, callee, framePointer, profileId, arrayProfileId, callInfo);
  391. return
  392. ProfiledNewScObjArray(
  393. callee,
  394. args,
  395. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject),
  396. profileId,
  397. arrayProfileId);
  398. }
  399. Var ProfilingHelpers::ProfiledNewScObjArraySpread_Jit(
  400. const Js::AuxArray<uint32> *spreadIndices,
  401. const Var callee,
  402. void *const framePointer,
  403. const ProfileId profileId,
  404. const ProfileId arrayProfileId,
  405. CallInfo callInfo,
  406. ...)
  407. {
  408. ARGUMENTS(args, callInfo);
  409. Js::ScriptFunction *function = ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  410. ScriptContext* scriptContext = function->GetScriptContext();
  411. // GetSpreadSize ensures that spreadSize < 2^24
  412. uint32 spreadSize = 0;
  413. if (spreadIndices != nullptr)
  414. {
  415. Arguments outArgs(CallInfo(args.Info.Flags, 0), nullptr);
  416. spreadSize = JavascriptFunction::GetSpreadSize(args, spreadIndices, scriptContext);
  417. Assert(spreadSize == (((1 << 24) - 1) & spreadSize));
  418. // Allocate room on the stack for the spread args.
  419. outArgs.Info.Count = spreadSize;
  420. const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
  421. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  422. size_t outArgsSize = 0;
  423. if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
  424. {
  425. PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
  426. outArgsSize = outArgs.Info.Count * sizeof(Var);
  427. outArgs.Values = (Var*)_alloca(outArgsSize);
  428. ZeroMemory(outArgs.Values, outArgsSize);
  429. }
  430. else
  431. {
  432. outArgs.Values = stackArgs;
  433. outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
  434. ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
  435. }
  436. JavascriptFunction::SpreadArgs(args, outArgs, spreadIndices, scriptContext);
  437. return
  438. ProfiledNewScObjArray(
  439. callee,
  440. outArgs,
  441. function,
  442. profileId,
  443. arrayProfileId);
  444. }
  445. else
  446. {
  447. return
  448. ProfiledNewScObjArray(
  449. callee,
  450. args,
  451. function,
  452. profileId,
  453. arrayProfileId);
  454. }
  455. }
  456. Var ProfilingHelpers::ProfiledNewScObjArray(
  457. const Var callee,
  458. const Arguments args,
  459. ScriptFunction *const caller,
  460. const ProfileId profileId,
  461. const ProfileId arrayProfileId)
  462. {
  463. Assert(callee);
  464. Assert(args.Info.Count != 0);
  465. Assert(caller);
  466. Assert(profileId != Constants::NoProfileId);
  467. Assert(arrayProfileId != Constants::NoProfileId);
  468. FunctionBody *const callerFunctionBody = caller->GetFunctionBody();
  469. DynamicProfileInfo *const profileInfo = callerFunctionBody->GetDynamicProfileInfo();
  470. ArrayCallSiteInfo *const arrayInfo = profileInfo->GetArrayCallSiteInfo(callerFunctionBody, arrayProfileId);
  471. Assert(arrayInfo);
  472. ScriptContext *const scriptContext = callerFunctionBody->GetScriptContext();
  473. FunctionInfo *const calleeFunctionInfo = JavascriptOperators::GetConstructorFunctionInfo(callee, scriptContext);
  474. if (calleeFunctionInfo != &JavascriptArray::EntryInfo::NewInstance)
  475. {
  476. // It may be worth checking the object that we actually got back from the ctor, but
  477. // we should at least not keep bailing out at this call site.
  478. arrayInfo->SetIsNotNativeArray();
  479. return ProfiledNewScObject(callee, args, callerFunctionBody, profileId);
  480. }
  481. profileInfo->RecordCallSiteInfo(
  482. callerFunctionBody,
  483. profileId,
  484. calleeFunctionInfo,
  485. caller,
  486. args.Info.Count,
  487. true);
  488. args.Values[0] = nullptr;
  489. Var array;
  490. if (arrayInfo->IsNativeIntArray())
  491. {
  492. array = JavascriptNativeIntArray::NewInstance(RecyclableObject::FromVar(callee), args);
  493. if (VirtualTableInfo<JavascriptNativeIntArray>::HasVirtualTable(array))
  494. {
  495. JavascriptNativeIntArray *const intArray = static_cast<JavascriptNativeIntArray *>(array);
  496. intArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
  497. }
  498. else
  499. {
  500. arrayInfo->SetIsNotNativeIntArray();
  501. if (VirtualTableInfo<JavascriptNativeFloatArray>::HasVirtualTable(array))
  502. {
  503. JavascriptNativeFloatArray *const floatArray = static_cast<JavascriptNativeFloatArray *>(array);
  504. floatArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
  505. }
  506. else
  507. {
  508. arrayInfo->SetIsNotNativeArray();
  509. }
  510. }
  511. }
  512. else if (arrayInfo->IsNativeFloatArray())
  513. {
  514. array = JavascriptNativeFloatArray::NewInstance(RecyclableObject::FromVar(callee), args);
  515. if (VirtualTableInfo<JavascriptNativeFloatArray>::HasVirtualTable(array))
  516. {
  517. JavascriptNativeFloatArray *const floatArray = static_cast<JavascriptNativeFloatArray *>(array);
  518. floatArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
  519. }
  520. else
  521. {
  522. arrayInfo->SetIsNotNativeArray();
  523. }
  524. }
  525. else
  526. {
  527. array = JavascriptArray::NewInstance(RecyclableObject::FromVar(callee), args);
  528. }
  529. return CrossSite::MarshalVar(scriptContext, array);
  530. }
  531. Var ProfilingHelpers::ProfiledNewScObject(
  532. const Var callee,
  533. const Arguments args,
  534. FunctionBody *const callerFunctionBody,
  535. const ProfileId profileId,
  536. const InlineCacheIndex inlineCacheIndex,
  537. const Js::AuxArray<uint32> *spreadIndices)
  538. {
  539. Assert(callee);
  540. Assert(args.Info.Count != 0);
  541. Assert(callerFunctionBody);
  542. Assert(profileId != Constants::NoProfileId);
  543. ScriptContext *const scriptContext = callerFunctionBody->GetScriptContext();
  544. if(!TaggedNumber::Is(callee))
  545. {
  546. const auto calleeObject = JavascriptOperators::GetCallableObjectOrThrow(callee, scriptContext);
  547. const auto calleeFunctionInfo =
  548. calleeObject->GetTypeId() == TypeIds_Function
  549. ? JavascriptFunction::FromVar(calleeObject)->GetFunctionInfo()
  550. : nullptr;
  551. DynamicProfileInfo *profileInfo = callerFunctionBody->GetDynamicProfileInfo();
  552. profileInfo->RecordCallSiteInfo(
  553. callerFunctionBody,
  554. profileId,
  555. calleeFunctionInfo,
  556. calleeFunctionInfo ? static_cast<JavascriptFunction *>(calleeObject) : nullptr,
  557. args.Info.Count,
  558. true,
  559. inlineCacheIndex);
  560. // We need to record information here, most importantly so that we handle array subclass
  561. // creation properly, since optimizing those cases is important
  562. Var retVal = JavascriptOperators::NewScObject(callee, args, scriptContext, spreadIndices);
  563. profileInfo->RecordReturnTypeOnCallSiteInfo(callerFunctionBody, profileId, retVal);
  564. return retVal;
  565. }
  566. return JavascriptOperators::NewScObject(callee, args, scriptContext, spreadIndices);
  567. }
  568. void ProfilingHelpers::ProfileLdSlot(const Var value, FunctionBody *const functionBody, const ProfileId profileId)
  569. {
  570. Assert(value);
  571. Assert(functionBody);
  572. Assert(profileId != Constants::NoProfileId);
  573. functionBody->GetDynamicProfileInfo()->RecordSlotLoad(functionBody, profileId, value);
  574. }
  575. Var ProfilingHelpers::ProfiledLdFld_Jit(
  576. const Var instance,
  577. const PropertyId propertyId,
  578. const InlineCacheIndex inlineCacheIndex,
  579. void *const framePointer)
  580. {
  581. ScriptFunction *const scriptFunction =
  582. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  583. return
  584. ProfiledLdFld<false, false, false>(
  585. instance,
  586. propertyId,
  587. GetInlineCache(scriptFunction, inlineCacheIndex),
  588. inlineCacheIndex,
  589. scriptFunction->GetFunctionBody(),
  590. instance);
  591. }
  592. Var ProfilingHelpers::ProfiledLdSuperFld_Jit(
  593. const Var instance,
  594. const PropertyId propertyId,
  595. const InlineCacheIndex inlineCacheIndex,
  596. void *const framePointer,
  597. const Var thisInstance)
  598. {
  599. ScriptFunction *const scriptFunction =
  600. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  601. return
  602. ProfiledLdFld<false, false, false>(
  603. instance,
  604. propertyId,
  605. GetInlineCache(scriptFunction, inlineCacheIndex),
  606. inlineCacheIndex,
  607. scriptFunction->GetFunctionBody(),
  608. thisInstance);
  609. }
  610. Var ProfilingHelpers::ProfiledLdFldForTypeOf_Jit(
  611. const Var instance,
  612. const PropertyId propertyId,
  613. const InlineCacheIndex inlineCacheIndex,
  614. void *const framePointer)
  615. {
  616. ScriptFunction *const scriptFunction =
  617. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  618. return ProfiledLdFldForTypeOf<false, false, false>(
  619. instance,
  620. propertyId,
  621. GetInlineCache(scriptFunction, inlineCacheIndex),
  622. inlineCacheIndex,
  623. scriptFunction->GetFunctionBody());
  624. }
  625. Var ProfilingHelpers::ProfiledLdFld_CallApplyTarget_Jit(
  626. const Var instance,
  627. const PropertyId propertyId,
  628. const InlineCacheIndex inlineCacheIndex,
  629. void *const framePointer)
  630. {
  631. ScriptFunction *const scriptFunction =
  632. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  633. return
  634. ProfiledLdFld<false, false, true>(
  635. instance,
  636. propertyId,
  637. GetInlineCache(scriptFunction, inlineCacheIndex),
  638. inlineCacheIndex,
  639. scriptFunction->GetFunctionBody(),
  640. instance);
  641. }
  642. Var ProfilingHelpers::ProfiledLdMethodFld_Jit(
  643. const Var instance,
  644. const PropertyId propertyId,
  645. const InlineCacheIndex inlineCacheIndex,
  646. void *const framePointer)
  647. {
  648. ScriptFunction *const scriptFunction =
  649. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  650. return
  651. ProfiledLdFld<false, true, false>(
  652. instance,
  653. propertyId,
  654. GetInlineCache(scriptFunction, inlineCacheIndex),
  655. inlineCacheIndex,
  656. scriptFunction->GetFunctionBody(),
  657. instance);
  658. }
  659. Var ProfilingHelpers::ProfiledLdRootFld_Jit(
  660. const Var instance,
  661. const PropertyId propertyId,
  662. const InlineCacheIndex inlineCacheIndex,
  663. void *const framePointer)
  664. {
  665. ScriptFunction *const scriptFunction =
  666. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  667. return
  668. ProfiledLdFld<true, false, false>(
  669. instance,
  670. propertyId,
  671. GetInlineCache(scriptFunction, inlineCacheIndex),
  672. inlineCacheIndex,
  673. scriptFunction->GetFunctionBody(),
  674. instance);
  675. }
  676. Var ProfilingHelpers::ProfiledLdRootFldForTypeOf_Jit(
  677. const Var instance,
  678. const PropertyId propertyId,
  679. const InlineCacheIndex inlineCacheIndex,
  680. void *const framePointer)
  681. {
  682. ScriptFunction *const scriptFunction =
  683. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  684. return ProfiledLdFldForTypeOf<true, false, false>(
  685. instance,
  686. propertyId,
  687. GetInlineCache(scriptFunction, inlineCacheIndex),
  688. inlineCacheIndex,
  689. scriptFunction->GetFunctionBody());
  690. }
  691. Var ProfilingHelpers::ProfiledLdRootMethodFld_Jit(
  692. const Var instance,
  693. const PropertyId propertyId,
  694. const InlineCacheIndex inlineCacheIndex,
  695. void *const framePointer)
  696. {
  697. ScriptFunction *const scriptFunction =
  698. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  699. return
  700. ProfiledLdFld<true, true, false>(
  701. instance,
  702. propertyId,
  703. GetInlineCache(scriptFunction, inlineCacheIndex),
  704. inlineCacheIndex,
  705. scriptFunction->GetFunctionBody(),
  706. instance);
  707. }
  708. template<bool Root, bool Method, bool CallApplyTarget>
  709. Var ProfilingHelpers::ProfiledLdFld(
  710. const Var instance,
  711. const PropertyId propertyId,
  712. InlineCache *const inlineCache,
  713. const InlineCacheIndex inlineCacheIndex,
  714. FunctionBody *const functionBody,
  715. const Var thisInstance)
  716. {
  717. Assert(instance);
  718. Assert(thisInstance);
  719. Assert(propertyId != Constants::NoProperty);
  720. Assert(inlineCache);
  721. Assert(functionBody);
  722. Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
  723. Assert(!Root || inlineCacheIndex >= functionBody->GetRootObjectLoadInlineCacheStart());
  724. #if ENABLE_COPYONACCESS_ARRAY
  725. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  726. #endif
  727. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  728. DynamicProfileInfo *const dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  729. Var value;
  730. FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
  731. if (Root || (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance)))
  732. {
  733. RecyclableObject *const object = RecyclableObject::FromVar(instance);
  734. RecyclableObject *const thisObject = RecyclableObject::FromVar(thisInstance);
  735. if (!Root && Method && (propertyId == PropertyIds::apply || propertyId == PropertyIds::call) && ScriptFunction::Is(object))
  736. {
  737. // If the property being loaded is "apply"/"call", make an optimistic assumption that apply/call is not overridden and
  738. // undefer the function right here if it was defer parsed before. This is required so that the load of "apply"/"call"
  739. // happens from the same "type". Otherwise, we will have a polymorphic cache for load of "apply"/"call".
  740. ScriptFunction *fn = ScriptFunction::FromVar(object);
  741. if (fn->GetType()->GetEntryPoint() == JavascriptFunction::DeferredParsingThunk)
  742. {
  743. JavascriptFunction::DeferredParse(&fn);
  744. }
  745. }
  746. PropertyCacheOperationInfo operationInfo;
  747. PropertyValueInfo propertyValueInfo;
  748. PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
  749. if (!CacheOperators::TryGetProperty<true, true, true, !Root && !Method, true, !Root, true, false, true>(
  750. thisObject,
  751. Root,
  752. object,
  753. propertyId,
  754. &value,
  755. scriptContext,
  756. &operationInfo,
  757. &propertyValueInfo))
  758. {
  759. const auto PatchGetValue = &JavascriptOperators::PatchGetValueWithThisPtrNoFastPath;
  760. const auto PatchGetRootValue = &JavascriptOperators::PatchGetRootValueNoFastPath_Var;
  761. const auto PatchGetMethod = &JavascriptOperators::PatchGetMethodNoFastPath;
  762. const auto PatchGetRootMethod = &JavascriptOperators::PatchGetRootMethodNoFastPath_Var;
  763. const auto PatchGet =
  764. Root
  765. ? Method ? PatchGetRootMethod : PatchGetRootValue
  766. : PatchGetMethod ;
  767. value = (!Root && !Method) ? PatchGetValue(functionBody, inlineCache, inlineCacheIndex, object, propertyId, thisObject) :
  768. PatchGet(functionBody, inlineCache, inlineCacheIndex, object, propertyId);
  769. CacheOperators::PretendTryGetProperty<true, false>(object->GetType(), &operationInfo, &propertyValueInfo);
  770. }
  771. else if (!Root && !Method)
  772. {
  773. // Inline cache hit. oldflags must match the new ones. If not there is mark it as polymorphic as there is likely
  774. // a bailout to interpreter and change in the inline cache type.
  775. const FldInfoFlags oldflags = dynamicProfileInfo->GetFldInfo(functionBody, inlineCacheIndex)->flags;
  776. if ((oldflags != FldInfo_NoInfo) &&
  777. !(oldflags & DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType)))
  778. {
  779. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
  780. }
  781. }
  782. if (propertyId == Js::PropertyIds::arguments)
  783. {
  784. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_FromAccessor);
  785. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
  786. }
  787. if (!Root && operationInfo.isPolymorphic)
  788. {
  789. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
  790. }
  791. fldInfoFlags =
  792. DynamicProfileInfo::MergeFldInfoFlags(
  793. fldInfoFlags,
  794. DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
  795. fldInfoFlags =
  796. DynamicProfileInfo::MergeFldInfoFlags(
  797. fldInfoFlags,
  798. DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
  799. if (!Method)
  800. {
  801. UpdateFldInfoFlagsForGetSetInlineCandidate(
  802. object,
  803. fldInfoFlags,
  804. operationInfo.cacheType,
  805. inlineCache,
  806. functionBody);
  807. if (!Root && CallApplyTarget)
  808. {
  809. UpdateFldInfoFlagsForCallApplyInlineCandidate(
  810. object,
  811. fldInfoFlags,
  812. operationInfo.cacheType,
  813. inlineCache,
  814. functionBody);
  815. }
  816. }
  817. }
  818. else
  819. {
  820. Assert(!Root);
  821. const auto PatchGetValue = &JavascriptOperators::PatchGetValue<false, InlineCache>;
  822. const auto PatchGetMethod = &JavascriptOperators::PatchGetMethod<false, InlineCache>;
  823. const auto PatchGet = Method ? PatchGetMethod : PatchGetValue;
  824. value = PatchGet(functionBody, inlineCache, inlineCacheIndex, instance, propertyId);
  825. }
  826. dynamicProfileInfo->RecordFieldAccess(functionBody, inlineCacheIndex, value, fldInfoFlags);
  827. return value;
  828. }
  829. template<bool Root, bool Method, bool CallApplyTarget>
  830. Var ProfilingHelpers::ProfiledLdFldForTypeOf(
  831. const Var instance,
  832. const PropertyId propertyId,
  833. InlineCache *const inlineCache,
  834. const InlineCacheIndex inlineCacheIndex,
  835. FunctionBody *const functionBody)
  836. {
  837. Var val = nullptr;
  838. ScriptContext *scriptContext = functionBody->GetScriptContext();
  839. BEGIN_PROFILED_TYPEOF_ERROR_HANDLER(scriptContext);
  840. val = ProfiledLdFld<Root, Method, CallApplyTarget>(
  841. instance,
  842. propertyId,
  843. inlineCache,
  844. inlineCacheIndex,
  845. functionBody,
  846. instance);
  847. END_PROFILED_TYPEOF_ERROR_HANDLER(scriptContext, val, functionBody, inlineCacheIndex);
  848. return val;
  849. }
  850. void ProfilingHelpers::ProfiledStFld_Jit(
  851. const Var instance,
  852. const PropertyId propertyId,
  853. const InlineCacheIndex inlineCacheIndex,
  854. const Var value,
  855. void *const framePointer)
  856. {
  857. ScriptFunction *const scriptFunction =
  858. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  859. ProfiledStFld<false>(
  860. instance,
  861. propertyId,
  862. GetInlineCache(scriptFunction, inlineCacheIndex),
  863. inlineCacheIndex,
  864. value,
  865. PropertyOperation_None,
  866. scriptFunction,
  867. instance);
  868. }
  869. void ProfilingHelpers::ProfiledStSuperFld_Jit(
  870. const Var instance,
  871. const PropertyId propertyId,
  872. const InlineCacheIndex inlineCacheIndex,
  873. const Var value,
  874. void *const framePointer,
  875. const Var thisInstance)
  876. {
  877. ScriptFunction *const scriptFunction =
  878. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  879. ProfiledStFld<false>(
  880. instance,
  881. propertyId,
  882. GetInlineCache(scriptFunction, inlineCacheIndex),
  883. inlineCacheIndex,
  884. value,
  885. PropertyOperation_None,
  886. scriptFunction,
  887. thisInstance);
  888. }
  889. void ProfilingHelpers::ProfiledStFld_Strict_Jit(
  890. const Var instance,
  891. const PropertyId propertyId,
  892. const InlineCacheIndex inlineCacheIndex,
  893. const Var value,
  894. void *const framePointer)
  895. {
  896. ScriptFunction *const scriptFunction =
  897. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  898. ProfiledStFld<false>(
  899. instance,
  900. propertyId,
  901. GetInlineCache(scriptFunction, inlineCacheIndex),
  902. inlineCacheIndex,
  903. value,
  904. PropertyOperation_StrictMode,
  905. scriptFunction,
  906. instance);
  907. }
  908. void ProfilingHelpers::ProfiledStRootFld_Jit(
  909. const Var instance,
  910. const PropertyId propertyId,
  911. const InlineCacheIndex inlineCacheIndex,
  912. const Var value,
  913. void *const framePointer)
  914. {
  915. ScriptFunction *const scriptFunction =
  916. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  917. ProfiledStFld<true>(
  918. instance,
  919. propertyId,
  920. GetInlineCache(scriptFunction, inlineCacheIndex),
  921. inlineCacheIndex,
  922. value,
  923. PropertyOperation_Root,
  924. scriptFunction,
  925. instance);
  926. }
  927. void ProfilingHelpers::ProfiledStRootFld_Strict_Jit(
  928. const Var instance,
  929. const PropertyId propertyId,
  930. const InlineCacheIndex inlineCacheIndex,
  931. const Var value,
  932. void *const framePointer)
  933. {
  934. ScriptFunction *const scriptFunction =
  935. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  936. ProfiledStFld<true>(
  937. instance,
  938. propertyId,
  939. GetInlineCache(scriptFunction, inlineCacheIndex),
  940. inlineCacheIndex,
  941. value,
  942. PropertyOperation_StrictModeRoot,
  943. scriptFunction,
  944. instance);
  945. }
  946. template<bool Root>
  947. void ProfilingHelpers::ProfiledStFld(
  948. const Var instance,
  949. const PropertyId propertyId,
  950. InlineCache *const inlineCache,
  951. const InlineCacheIndex inlineCacheIndex,
  952. const Var value,
  953. const PropertyOperationFlags flags,
  954. ScriptFunction *const scriptFunction,
  955. const Var thisInstance)
  956. {
  957. Assert(instance);
  958. Assert(thisInstance);
  959. Assert(propertyId != Constants::NoProperty);
  960. Assert(inlineCache);
  961. Assert(scriptFunction);
  962. FunctionBody *const functionBody = scriptFunction->GetFunctionBody();
  963. Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
  964. Assert(value);
  965. #if ENABLE_COPYONACCESS_ARRAY
  966. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  967. #endif
  968. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  969. FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
  970. if(Root || (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance)))
  971. {
  972. RecyclableObject *const object = RecyclableObject::FromVar(instance);
  973. RecyclableObject *const thisObject = RecyclableObject::FromVar(thisInstance);
  974. PropertyCacheOperationInfo operationInfo;
  975. PropertyValueInfo propertyValueInfo;
  976. PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
  977. if(!CacheOperators::TrySetProperty<true, true, true, true, !Root, true, false, true>(
  978. thisObject,
  979. Root,
  980. propertyId,
  981. value,
  982. scriptContext,
  983. flags,
  984. &operationInfo,
  985. &propertyValueInfo))
  986. {
  987. ThreadContext* threadContext = scriptContext->GetThreadContext();
  988. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  989. threadContext->ClearImplicitCallFlags();
  990. Type *const oldType = object->GetType();
  991. if (Root)
  992. {
  993. JavascriptOperators::PatchPutRootValueNoFastPath(functionBody, inlineCache, inlineCacheIndex, object, propertyId, value, flags);
  994. }
  995. else
  996. {
  997. JavascriptOperators::PatchPutValueWithThisPtrNoFastPath(functionBody, inlineCache, inlineCacheIndex, object, propertyId, value, thisObject, flags);
  998. }
  999. CacheOperators::PretendTrySetProperty<true, false>(
  1000. object->GetType(),
  1001. oldType,
  1002. &operationInfo,
  1003. &propertyValueInfo);
  1004. // Setting to __proto__ property invokes a setter and changes the prototype.So, although PatchPut* populates the cache,
  1005. // the setter invalidates it (since it changes the prototype). PretendTrySetProperty looks at the inline cache type to
  1006. // update the cacheType on PropertyOperationInfo, which is used in populating the field info flags for this operation on
  1007. // the profile. Since the cache was invalidated, we don't get a match with either the type of the object with property or
  1008. // without it and the cacheType defaults to CacheType_None. This leads the profile info to say that this operation doesn't
  1009. // cause an accessor implicit call and JIT then doesn't kill live fields across it and ends up putting a BailOutOnImplicitCalls
  1010. // if there were live fields. This bailout always bails out.
  1011. Js::ImplicitCallFlags accessorCallFlag = (Js::ImplicitCallFlags)(Js::ImplicitCall_Accessor & ~Js::ImplicitCall_None);
  1012. if ((threadContext->GetImplicitCallFlags() & accessorCallFlag) != 0)
  1013. {
  1014. operationInfo.cacheType = CacheType_Setter;
  1015. }
  1016. threadContext->SetImplicitCallFlags((Js::ImplicitCallFlags)(savedImplicitCallFlags | threadContext->GetImplicitCallFlags()));
  1017. }
  1018. // Only make the field polymorphic if we are not using the root object inline cache
  1019. if(operationInfo.isPolymorphic && inlineCacheIndex < functionBody->GetRootObjectStoreInlineCacheStart())
  1020. {
  1021. // should not be a load inline cache
  1022. Assert(inlineCacheIndex < functionBody->GetRootObjectLoadInlineCacheStart());
  1023. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
  1024. }
  1025. fldInfoFlags =
  1026. DynamicProfileInfo::MergeFldInfoFlags(
  1027. fldInfoFlags,
  1028. DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
  1029. fldInfoFlags =
  1030. DynamicProfileInfo::MergeFldInfoFlags(
  1031. fldInfoFlags,
  1032. DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
  1033. UpdateFldInfoFlagsForGetSetInlineCandidate(
  1034. object,
  1035. fldInfoFlags,
  1036. operationInfo.cacheType,
  1037. inlineCache,
  1038. functionBody);
  1039. if(scriptFunction->GetConstructorCache()->NeedsUpdateAfterCtor())
  1040. {
  1041. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  1042. // function object's constructor cache will be updated with the type produced by the constructor. From that
  1043. // point on, when the same function object is used as a constructor, the a new object with the final type will
  1044. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  1045. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  1046. inlineCache->Clear();
  1047. }
  1048. }
  1049. else
  1050. {
  1051. JavascriptOperators::PatchPutValueNoLocalFastPath<false>(
  1052. functionBody,
  1053. inlineCache,
  1054. inlineCacheIndex,
  1055. instance,
  1056. propertyId,
  1057. value,
  1058. flags);
  1059. }
  1060. functionBody->GetDynamicProfileInfo()->RecordFieldAccess(functionBody, inlineCacheIndex, nullptr, fldInfoFlags);
  1061. }
  1062. void ProfilingHelpers::ProfiledInitFld_Jit(
  1063. const Var instance,
  1064. const PropertyId propertyId,
  1065. const InlineCacheIndex inlineCacheIndex,
  1066. const Var value,
  1067. void *const framePointer)
  1068. {
  1069. ScriptFunction *const scriptFunction =
  1070. ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
  1071. ProfiledInitFld(
  1072. RecyclableObject::FromVar(instance),
  1073. propertyId,
  1074. GetInlineCache(scriptFunction, inlineCacheIndex),
  1075. inlineCacheIndex,
  1076. value,
  1077. scriptFunction->GetFunctionBody());
  1078. }
  1079. void ProfilingHelpers::ProfiledInitFld(
  1080. RecyclableObject *const object,
  1081. const PropertyId propertyId,
  1082. InlineCache *const inlineCache,
  1083. const InlineCacheIndex inlineCacheIndex,
  1084. const Var value,
  1085. FunctionBody *const functionBody)
  1086. {
  1087. Assert(object);
  1088. Assert(propertyId != Constants::NoProperty);
  1089. Assert(inlineCache);
  1090. Assert(functionBody);
  1091. Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
  1092. Assert(value);
  1093. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  1094. FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
  1095. PropertyCacheOperationInfo operationInfo;
  1096. PropertyValueInfo propertyValueInfo;
  1097. PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
  1098. if(!CacheOperators::TrySetProperty<true, true, true, true, true, true, false, true>(
  1099. object,
  1100. false,
  1101. propertyId,
  1102. value,
  1103. scriptContext,
  1104. PropertyOperation_None,
  1105. &operationInfo,
  1106. &propertyValueInfo))
  1107. {
  1108. Type *const oldType = object->GetType();
  1109. JavascriptOperators::PatchInitValueNoFastPath(
  1110. functionBody,
  1111. inlineCache,
  1112. inlineCacheIndex,
  1113. object,
  1114. propertyId,
  1115. value);
  1116. CacheOperators::PretendTrySetProperty<true, false>(object->GetType(), oldType, &operationInfo, &propertyValueInfo);
  1117. }
  1118. // Only make the field polymorphic if the we are not using the root object inline cache
  1119. if(operationInfo.isPolymorphic && inlineCacheIndex < functionBody->GetRootObjectStoreInlineCacheStart())
  1120. {
  1121. // should not be a load inline cache
  1122. Assert(inlineCacheIndex < functionBody->GetRootObjectLoadInlineCacheStart());
  1123. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
  1124. }
  1125. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
  1126. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
  1127. functionBody->GetDynamicProfileInfo()->RecordFieldAccess(functionBody, inlineCacheIndex, nullptr, fldInfoFlags);
  1128. }
  1129. void ProfilingHelpers::UpdateFldInfoFlagsForGetSetInlineCandidate(
  1130. RecyclableObject *const object,
  1131. FldInfoFlags &fldInfoFlags,
  1132. const CacheType cacheType,
  1133. InlineCache *const inlineCache,
  1134. FunctionBody *const functionBody)
  1135. {
  1136. RecyclableObject *callee = nullptr;
  1137. if((cacheType & (CacheType_Getter | CacheType_Setter)) &&
  1138. inlineCache->GetGetterSetter(object->GetType(), &callee))
  1139. {
  1140. const bool canInline = functionBody->GetDynamicProfileInfo()->RecordLdFldCallSiteInfo(functionBody, callee, false /*callApplyTarget*/);
  1141. if(canInline)
  1142. {
  1143. //updates this fldInfoFlags passed by reference.
  1144. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  1145. }
  1146. }
  1147. }
  1148. void ProfilingHelpers::UpdateFldInfoFlagsForCallApplyInlineCandidate(
  1149. RecyclableObject *const object,
  1150. FldInfoFlags &fldInfoFlags,
  1151. const CacheType cacheType,
  1152. InlineCache *const inlineCache,
  1153. FunctionBody *const functionBody)
  1154. {
  1155. RecyclableObject *callee = nullptr;
  1156. if(!(fldInfoFlags & FldInfo_Polymorphic) && inlineCache->GetCallApplyTarget(object, &callee))
  1157. {
  1158. const bool canInline = functionBody->GetDynamicProfileInfo()->RecordLdFldCallSiteInfo(functionBody, callee, true /*callApplyTarget*/);
  1159. if(canInline)
  1160. {
  1161. //updates the fldInfoFlags passed by reference.
  1162. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  1163. }
  1164. }
  1165. }
  1166. InlineCache *ProfilingHelpers::GetInlineCache(ScriptFunction *const scriptFunction, const InlineCacheIndex inlineCacheIndex)
  1167. {
  1168. Assert(scriptFunction);
  1169. Assert(inlineCacheIndex < scriptFunction->GetFunctionBody()->GetInlineCacheCount());
  1170. return
  1171. scriptFunction->GetHasInlineCaches()
  1172. ? ScriptFunctionWithInlineCache::FromVar(scriptFunction)->GetInlineCache(inlineCacheIndex)
  1173. : scriptFunction->GetFunctionBody()->GetInlineCache(inlineCacheIndex);
  1174. }
  1175. #endif
  1176. }