| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeLanguagePch.h"
- namespace Js
- {
- #if ENABLE_PROFILE_INFO
- Var ProfilingHelpers::ProfiledLdElem(
- const Var base,
- const Var varIndex,
- FunctionBody *const functionBody,
- const ProfileId profileId)
- {
- Assert(base);
- Assert(varIndex);
- Assert(functionBody);
- Assert(profileId != Constants::NoProfileId);
- LdElemInfo ldElemInfo;
- // Only enable fast path if the javascript array is not cross site
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(base);
- #endif
- const bool isJsArray = !TaggedNumber::Is(base) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(base);
- const bool fastPath = isJsArray;
- if(fastPath)
- {
- JavascriptArray *const array = JavascriptArray::FromVar(base);
- ldElemInfo.arrayType = ValueType::FromArray(ObjectType::Array, array, TypeIds_Array).ToLikely();
- const Var element = ProfiledLdElem_FastPath(array, varIndex, functionBody->GetScriptContext(), &ldElemInfo);
- ldElemInfo.elemType = ldElemInfo.elemType.Merge(element);
- functionBody->GetDynamicProfileInfo()->RecordElementLoad(functionBody, profileId, ldElemInfo);
- return element;
- }
- Assert(!isJsArray);
- bool isObjectWithArray;
- TypeId arrayTypeId;
- JavascriptArray *const array =
- JavascriptArray::GetArrayForArrayOrObjectWithArray(base, &isObjectWithArray, &arrayTypeId);
- do // while(false)
- {
- // The fast path is only for JavascriptArray and doesn't cover native arrays, objects with internal arrays, or typed
- // arrays, but we still need to profile the array
- uint32 headSegmentLength;
- if(array)
- {
- ldElemInfo.arrayType =
- (
- isObjectWithArray
- ? ValueType::FromObjectArray(array)
- : ValueType::FromArray(ObjectType::Array, array, arrayTypeId)
- ).ToLikely();
- SparseArraySegmentBase *const head = array->GetHead();
- Assert(head->left == 0);
- headSegmentLength = head->length;
- }
- else if(TypedArrayBase::TryGetLengthForOptimizedTypedArray(base, &headSegmentLength, &arrayTypeId))
- {
- bool isVirtual = (VirtualTableInfoBase::GetVirtualTable(base) == ValueType::GetVirtualTypedArrayVtable(arrayTypeId));
- ldElemInfo.arrayType = ValueType::FromTypeId(arrayTypeId, isVirtual).ToLikely();
- }
- else
- {
- break;
- }
- if(!TaggedInt::Is(varIndex))
- {
- ldElemInfo.neededHelperCall = true;
- break;
- }
- const int32 index = TaggedInt::ToInt32(varIndex);
- const uint32 offset = index;
- if(index < 0 || offset >= headSegmentLength || (array && array->IsMissingHeadSegmentItem(offset)))
- {
- ldElemInfo.neededHelperCall = true;
- break;
- }
- } while(false);
- const Var element = JavascriptOperators::OP_GetElementI(base, varIndex, functionBody->GetScriptContext());
- const ValueType arrayType(ldElemInfo.GetArrayType());
- if(!arrayType.IsUninitialized())
- {
- if(arrayType.IsLikelyObject() && arrayType.GetObjectType() == ObjectType::Array && !arrayType.HasIntElements())
- {
- JavascriptOperators::UpdateNativeArrayProfileInfoToCreateVarArray(
- array,
- arrayType.HasFloatElements(),
- arrayType.HasVarElements());
- }
- ldElemInfo.elemType = ValueType::Uninitialized.Merge(element);
- functionBody->GetDynamicProfileInfo()->RecordElementLoad(functionBody, profileId, ldElemInfo);
- return element;
- }
- functionBody->GetDynamicProfileInfo()->RecordElementLoadAsProfiled(functionBody, profileId);
- return element;
- }
- Var ProfilingHelpers::ProfiledLdElem_FastPath(
- JavascriptArray *const array,
- const Var varIndex,
- ScriptContext *const scriptContext,
- LdElemInfo *const ldElemInfo)
- {
- Assert(array);
- Assert(varIndex);
- Assert(scriptContext);
- do // while(false)
- {
- Assert(!array->IsCrossSiteObject());
- if (!TaggedInt::Is(varIndex))
- {
- break;
- }
- int32 index = TaggedInt::ToInt32(varIndex);
- if (index < 0)
- {
- break;
- }
- if(ldElemInfo)
- {
- SparseArraySegment<Var> *const head = static_cast<SparseArraySegment<Var> *>(array->GetHead());
- Assert(head->left == 0);
- const uint32 offset = index;
- if(offset < head->length)
- {
- const Var element = head->elements[offset];
- if(!SparseArraySegment<Var>::IsMissingItem(&element))
- {
- // Successful fastpath
- return element;
- }
- }
- ldElemInfo->neededHelperCall = true;
- }
- SparseArraySegment<Var> *seg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
- if ((uint32) index < seg->left)
- {
- break;
- }
- uint32 index2 = index - seg->left;
- if (index2 < seg->length)
- {
- Var elem = seg->elements[index2];
- if (elem != SparseArraySegment<Var>::GetMissingItem())
- {
- // Successful fastpath
- return elem;
- }
- }
- } while(false);
- if(ldElemInfo)
- {
- ldElemInfo->neededHelperCall = true;
- }
- return JavascriptOperators::OP_GetElementI(array, varIndex, scriptContext);
- }
- void ProfilingHelpers::ProfiledStElem_DefaultFlags(
- const Var base,
- const Var varIndex,
- const Var value,
- FunctionBody *const functionBody,
- const ProfileId profileId)
- {
- ProfiledStElem(base, varIndex, value, functionBody, profileId, PropertyOperation_None);
- }
- void ProfilingHelpers::ProfiledStElem(
- const Var base,
- const Var varIndex,
- const Var value,
- FunctionBody *const functionBody,
- const ProfileId profileId,
- const PropertyOperationFlags flags)
- {
- Assert(base);
- Assert(varIndex);
- Assert(value);
- Assert(functionBody);
- Assert(profileId != Constants::NoProfileId);
- StElemInfo stElemInfo;
- // Only enable fast path if the javascript array is not cross site
- const bool isJsArray = !TaggedNumber::Is(base) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(base);
- ScriptContext *const scriptContext = functionBody->GetScriptContext();
- const bool fastPath = isJsArray && !JavascriptOperators::SetElementMayHaveImplicitCalls(scriptContext);
- if(fastPath)
- {
- JavascriptArray *const array = JavascriptArray::FromVar(base);
- stElemInfo.arrayType = ValueType::FromArray(ObjectType::Array, array, TypeIds_Array).ToLikely();
- stElemInfo.createdMissingValue = array->HasNoMissingValues();
- ProfiledStElem_FastPath(array, varIndex, value, scriptContext, flags, &stElemInfo);
- stElemInfo.createdMissingValue &= !array->HasNoMissingValues();
- functionBody->GetDynamicProfileInfo()->RecordElementStore(functionBody, profileId, stElemInfo);
- return;
- }
- JavascriptArray *array;
- bool isObjectWithArray;
- TypeId arrayTypeId;
- if(isJsArray)
- {
- array = JavascriptArray::FromVar(base);
- isObjectWithArray = false;
- arrayTypeId = TypeIds_Array;
- }
- else
- {
- array = JavascriptArray::GetArrayForArrayOrObjectWithArray(base, &isObjectWithArray, &arrayTypeId);
- }
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(base);
- #endif
- do // while(false)
- {
- // The fast path is only for JavascriptArray and doesn't cover native arrays, objects with internal arrays, or typed
- // arrays, but we still need to profile the array
- uint32 length;
- uint32 headSegmentLength;
- if(array)
- {
- stElemInfo.arrayType =
- (
- isObjectWithArray
- ? ValueType::FromObjectArray(array)
- : ValueType::FromArray(ObjectType::Array, array, arrayTypeId)
- ).ToLikely();
- stElemInfo.createdMissingValue = array->HasNoMissingValues();
- length = array->GetLength();
- SparseArraySegmentBase *const head = array->GetHead();
- Assert(head->left == 0);
- headSegmentLength = head->length;
- }
- else if(TypedArrayBase::TryGetLengthForOptimizedTypedArray(base, &headSegmentLength, &arrayTypeId))
- {
- length = headSegmentLength;
- bool isVirtual = (VirtualTableInfoBase::GetVirtualTable(base) == ValueType::GetVirtualTypedArrayVtable(arrayTypeId));
- stElemInfo.arrayType = ValueType::FromTypeId(arrayTypeId, isVirtual).ToLikely();
- }
- else
- {
- break;
- }
- if(!TaggedInt::Is(varIndex))
- {
- stElemInfo.neededHelperCall = true;
- break;
- }
- const int32 index = TaggedInt::ToInt32(varIndex);
- if(index < 0)
- {
- stElemInfo.neededHelperCall = true;
- break;
- }
- const uint32 offset = index;
- if(offset >= headSegmentLength)
- {
- stElemInfo.storedOutsideHeadSegmentBounds = true;
- if(!isObjectWithArray && offset >= length)
- {
- stElemInfo.storedOutsideArrayBounds = true;
- }
- break;
- }
- if(array && array->IsMissingHeadSegmentItem(offset))
- {
- stElemInfo.filledMissingValue = true;
- }
- } while(false);
- JavascriptOperators::OP_SetElementI(base, varIndex, value, scriptContext, flags);
- if(!stElemInfo.GetArrayType().IsUninitialized())
- {
- if(array)
- {
- stElemInfo.createdMissingValue &= !array->HasNoMissingValues();
- }
- functionBody->GetDynamicProfileInfo()->RecordElementStore(functionBody, profileId, stElemInfo);
- return;
- }
- functionBody->GetDynamicProfileInfo()->RecordElementStoreAsProfiled(functionBody, profileId);
- }
- void ProfilingHelpers::ProfiledStElem_FastPath(
- JavascriptArray *const array,
- const Var varIndex,
- const Var value,
- ScriptContext *const scriptContext,
- const PropertyOperationFlags flags,
- StElemInfo *const stElemInfo)
- {
- Assert(array);
- Assert(varIndex);
- Assert(value);
- Assert(scriptContext);
- Assert(!JavascriptOperators::SetElementMayHaveImplicitCalls(scriptContext));
- do // while(false)
- {
- if (!TaggedInt::Is(varIndex))
- {
- break;
- }
- int32 index = TaggedInt::ToInt32(varIndex);
- if (index < 0)
- {
- break;
- }
- if(stElemInfo)
- {
- SparseArraySegmentBase *const head = array->GetHead();
- Assert(head->left == 0);
- const uint32 offset = index;
- if(offset >= head->length)
- {
- stElemInfo->storedOutsideHeadSegmentBounds = true;
- if(offset >= array->GetLength())
- {
- stElemInfo->storedOutsideArrayBounds = true;
- }
- }
- if(offset < head->size)
- {
- array->DirectProfiledSetItemInHeadSegmentAt(offset, value, stElemInfo);
- return;
- }
- }
- SparseArraySegment<Var>* lastUsedSeg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
- if (lastUsedSeg == NULL ||
- (uint32) index < lastUsedSeg->left)
- {
- break;
- }
- uint32 index2 = index - lastUsedSeg->left;
- if (index2 < lastUsedSeg->size)
- {
- // Successful fastpath
- array->DirectSetItemInLastUsedSegmentAt(index2, value);
- return;
- }
- } while(false);
- if(stElemInfo)
- {
- stElemInfo->neededHelperCall = true;
- }
- JavascriptOperators::OP_SetElementI(array, varIndex, value, scriptContext, flags);
- }
- JavascriptArray *ProfilingHelpers::ProfiledNewScArray(
- const uint length,
- FunctionBody *const functionBody,
- const ProfileId profileId)
- {
- Assert(functionBody);
- Assert(profileId != Constants::NoProfileId);
- // Not creating native array here if the function is unoptimized, because it turns out to be tricky to
- // get the initialization right if GlobOpt doesn't give us bailout. It's possible, but we should see
- // a use case before spending time on it.
- ArrayCallSiteInfo *const arrayInfo =
- functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
- Assert(arrayInfo);
- if (length > SparseArraySegmentBase::INLINE_CHUNK_SIZE || (functionBody->GetHasTry() && PHASE_OFF((Js::OptimizeTryCatchPhase), functionBody)))
- {
- arrayInfo->SetIsNotNativeArray();
- }
- ScriptContext *const scriptContext = functionBody->GetScriptContext();
- JavascriptArray *array;
- if (arrayInfo->IsNativeIntArray())
- {
- JavascriptNativeIntArray *const intArray = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(length);
- Recycler *recycler = scriptContext->GetRecycler();
- intArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
- array = intArray;
- }
- else if (arrayInfo->IsNativeFloatArray())
- {
- JavascriptNativeFloatArray *const floatArray = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(length);
- Recycler *recycler = scriptContext->GetRecycler();
- floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
- array = floatArray;
- }
- else
- {
- array = scriptContext->GetLibrary()->CreateArrayLiteral(length);
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- array->CheckForceES5Array();
- #endif
- return array;
- }
- Var ProfilingHelpers::ProfiledNewScObjArray_Jit(
- const Var callee,
- void *const framePointer,
- const ProfileId profileId,
- const ProfileId arrayProfileId,
- CallInfo callInfo,
- ...)
- {
- ARGUMENTS(args, callee, framePointer, profileId, arrayProfileId, callInfo);
- return
- ProfiledNewScObjArray(
- callee,
- args,
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject),
- profileId,
- arrayProfileId);
- }
- Var ProfilingHelpers::ProfiledNewScObjArraySpread_Jit(
- const Js::AuxArray<uint32> *spreadIndices,
- const Var callee,
- void *const framePointer,
- const ProfileId profileId,
- const ProfileId arrayProfileId,
- CallInfo callInfo,
- ...)
- {
- ARGUMENTS(args, callInfo);
- Js::ScriptFunction *function = ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ScriptContext* scriptContext = function->GetScriptContext();
- // GetSpreadSize ensures that spreadSize < 2^24
- uint32 spreadSize = 0;
- if (spreadIndices != nullptr)
- {
- Arguments outArgs(CallInfo(args.Info.Flags, 0), nullptr);
- spreadSize = JavascriptFunction::GetSpreadSize(args, spreadIndices, scriptContext);
- Assert(spreadSize == (((1 << 24) - 1) & spreadSize));
- // Allocate room on the stack for the spread args.
- outArgs.Info.Count = spreadSize;
- const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
- Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
- size_t outArgsSize = 0;
- if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
- {
- PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
- outArgsSize = outArgs.Info.Count * sizeof(Var);
- outArgs.Values = (Var*)_alloca(outArgsSize);
- ZeroMemory(outArgs.Values, outArgsSize);
- }
- else
- {
- outArgs.Values = stackArgs;
- outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
- ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
- }
- JavascriptFunction::SpreadArgs(args, outArgs, spreadIndices, scriptContext);
- return
- ProfiledNewScObjArray(
- callee,
- outArgs,
- function,
- profileId,
- arrayProfileId);
- }
- else
- {
- return
- ProfiledNewScObjArray(
- callee,
- args,
- function,
- profileId,
- arrayProfileId);
- }
- }
- Var ProfilingHelpers::ProfiledNewScObjArray(
- const Var callee,
- const Arguments args,
- ScriptFunction *const caller,
- const ProfileId profileId,
- const ProfileId arrayProfileId)
- {
- Assert(callee);
- Assert(args.Info.Count != 0);
- Assert(caller);
- Assert(profileId != Constants::NoProfileId);
- Assert(arrayProfileId != Constants::NoProfileId);
- FunctionBody *const callerFunctionBody = caller->GetFunctionBody();
- DynamicProfileInfo *const profileInfo = callerFunctionBody->GetDynamicProfileInfo();
- ArrayCallSiteInfo *const arrayInfo = profileInfo->GetArrayCallSiteInfo(callerFunctionBody, arrayProfileId);
- Assert(arrayInfo);
- ScriptContext *const scriptContext = callerFunctionBody->GetScriptContext();
- FunctionInfo *const calleeFunctionInfo = JavascriptOperators::GetConstructorFunctionInfo(callee, scriptContext);
- if (calleeFunctionInfo != &JavascriptArray::EntryInfo::NewInstance)
- {
- // It may be worth checking the object that we actually got back from the ctor, but
- // we should at least not keep bailing out at this call site.
- arrayInfo->SetIsNotNativeArray();
- return ProfiledNewScObject(callee, args, callerFunctionBody, profileId);
- }
- profileInfo->RecordCallSiteInfo(
- callerFunctionBody,
- profileId,
- calleeFunctionInfo,
- caller,
- args.Info.Count,
- true);
- args.Values[0] = nullptr;
- Var array;
- if (arrayInfo->IsNativeIntArray())
- {
- array = JavascriptNativeIntArray::NewInstance(RecyclableObject::FromVar(callee), args);
- if (VirtualTableInfo<JavascriptNativeIntArray>::HasVirtualTable(array))
- {
- JavascriptNativeIntArray *const intArray = static_cast<JavascriptNativeIntArray *>(array);
- intArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
- }
- else
- {
- arrayInfo->SetIsNotNativeIntArray();
- if (VirtualTableInfo<JavascriptNativeFloatArray>::HasVirtualTable(array))
- {
- JavascriptNativeFloatArray *const floatArray = static_cast<JavascriptNativeFloatArray *>(array);
- floatArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
- }
- else
- {
- arrayInfo->SetIsNotNativeArray();
- }
- }
- }
- else if (arrayInfo->IsNativeFloatArray())
- {
- array = JavascriptNativeFloatArray::NewInstance(RecyclableObject::FromVar(callee), args);
- if (VirtualTableInfo<JavascriptNativeFloatArray>::HasVirtualTable(array))
- {
- JavascriptNativeFloatArray *const floatArray = static_cast<JavascriptNativeFloatArray *>(array);
- floatArray->SetArrayCallSite(arrayProfileId, scriptContext->GetRecycler()->CreateWeakReferenceHandle(callerFunctionBody));
- }
- else
- {
- arrayInfo->SetIsNotNativeArray();
- }
- }
- else
- {
- array = JavascriptArray::NewInstance(RecyclableObject::FromVar(callee), args);
- }
- return CrossSite::MarshalVar(scriptContext, array);
- }
- Var ProfilingHelpers::ProfiledNewScObject(
- const Var callee,
- const Arguments args,
- FunctionBody *const callerFunctionBody,
- const ProfileId profileId,
- const InlineCacheIndex inlineCacheIndex,
- const Js::AuxArray<uint32> *spreadIndices)
- {
- Assert(callee);
- Assert(args.Info.Count != 0);
- Assert(callerFunctionBody);
- Assert(profileId != Constants::NoProfileId);
- ScriptContext *const scriptContext = callerFunctionBody->GetScriptContext();
- if(!TaggedNumber::Is(callee))
- {
- const auto calleeObject = JavascriptOperators::GetCallableObjectOrThrow(callee, scriptContext);
- const auto calleeFunctionInfo =
- calleeObject->GetTypeId() == TypeIds_Function
- ? JavascriptFunction::FromVar(calleeObject)->GetFunctionInfo()
- : nullptr;
- DynamicProfileInfo *profileInfo = callerFunctionBody->GetDynamicProfileInfo();
- profileInfo->RecordCallSiteInfo(
- callerFunctionBody,
- profileId,
- calleeFunctionInfo,
- calleeFunctionInfo ? static_cast<JavascriptFunction *>(calleeObject) : nullptr,
- args.Info.Count,
- true,
- inlineCacheIndex);
- // We need to record information here, most importantly so that we handle array subclass
- // creation properly, since optimizing those cases is important
- Var retVal = JavascriptOperators::NewScObject(callee, args, scriptContext, spreadIndices);
- profileInfo->RecordReturnTypeOnCallSiteInfo(callerFunctionBody, profileId, retVal);
- return retVal;
- }
- return JavascriptOperators::NewScObject(callee, args, scriptContext, spreadIndices);
- }
- void ProfilingHelpers::ProfileLdSlot(const Var value, FunctionBody *const functionBody, const ProfileId profileId)
- {
- Assert(value);
- Assert(functionBody);
- Assert(profileId != Constants::NoProfileId);
- functionBody->GetDynamicProfileInfo()->RecordSlotLoad(functionBody, profileId, value);
- }
- Var ProfilingHelpers::ProfiledLdFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<false, false, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- instance);
- }
- Var ProfilingHelpers::ProfiledLdSuperFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer,
- const Var thisInstance)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<false, false, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- thisInstance);
- }
- Var ProfilingHelpers::ProfiledLdFldForTypeOf_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return ProfiledLdFldForTypeOf<false, false, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody());
- }
- Var ProfilingHelpers::ProfiledLdFld_CallApplyTarget_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<false, false, true>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- instance);
- }
- Var ProfilingHelpers::ProfiledLdMethodFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<false, true, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- instance);
- }
- Var ProfilingHelpers::ProfiledLdRootFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<true, false, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- instance);
- }
- Var ProfilingHelpers::ProfiledLdRootFldForTypeOf_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return ProfiledLdFldForTypeOf<true, false, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody());
- }
- Var ProfilingHelpers::ProfiledLdRootMethodFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- return
- ProfiledLdFld<true, true, false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- scriptFunction->GetFunctionBody(),
- instance);
- }
- template<bool Root, bool Method, bool CallApplyTarget>
- Var ProfilingHelpers::ProfiledLdFld(
- const Var instance,
- const PropertyId propertyId,
- InlineCache *const inlineCache,
- const InlineCacheIndex inlineCacheIndex,
- FunctionBody *const functionBody,
- const Var thisInstance)
- {
- Assert(instance);
- Assert(thisInstance);
- Assert(propertyId != Constants::NoProperty);
- Assert(inlineCache);
- Assert(functionBody);
- Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
- Assert(!Root || inlineCacheIndex >= functionBody->GetRootObjectLoadInlineCacheStart());
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
- #endif
- ScriptContext *const scriptContext = functionBody->GetScriptContext();
- DynamicProfileInfo *const dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- Var value;
- FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
- if (Root || (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance)))
- {
- RecyclableObject *const object = RecyclableObject::FromVar(instance);
- RecyclableObject *const thisObject = RecyclableObject::FromVar(thisInstance);
- if (!Root && Method && (propertyId == PropertyIds::apply || propertyId == PropertyIds::call) && ScriptFunction::Is(object))
- {
- // If the property being loaded is "apply"/"call", make an optimistic assumption that apply/call is not overridden and
- // undefer the function right here if it was defer parsed before. This is required so that the load of "apply"/"call"
- // happens from the same "type". Otherwise, we will have a polymorphic cache for load of "apply"/"call".
- ScriptFunction *fn = ScriptFunction::FromVar(object);
- if (fn->GetType()->GetEntryPoint() == JavascriptFunction::DeferredParsingThunk)
- {
- JavascriptFunction::DeferredParse(&fn);
- }
- }
- PropertyCacheOperationInfo operationInfo;
- PropertyValueInfo propertyValueInfo;
- PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
- if (!CacheOperators::TryGetProperty<true, true, true, !Root && !Method, true, !Root, true, false, true>(
- thisObject,
- Root,
- object,
- propertyId,
- &value,
- scriptContext,
- &operationInfo,
- &propertyValueInfo))
- {
- const auto PatchGetValue = &JavascriptOperators::PatchGetValueWithThisPtrNoFastPath;
- const auto PatchGetRootValue = &JavascriptOperators::PatchGetRootValueNoFastPath_Var;
- const auto PatchGetMethod = &JavascriptOperators::PatchGetMethodNoFastPath;
- const auto PatchGetRootMethod = &JavascriptOperators::PatchGetRootMethodNoFastPath_Var;
- const auto PatchGet =
- Root
- ? Method ? PatchGetRootMethod : PatchGetRootValue
- : PatchGetMethod ;
- value = (!Root && !Method) ? PatchGetValue(functionBody, inlineCache, inlineCacheIndex, object, propertyId, thisObject) :
- PatchGet(functionBody, inlineCache, inlineCacheIndex, object, propertyId);
- CacheOperators::PretendTryGetProperty<true, false>(object->GetType(), &operationInfo, &propertyValueInfo);
- }
- else if (!Root && !Method)
- {
- // Inline cache hit. oldflags must match the new ones. If not there is mark it as polymorphic as there is likely
- // a bailout to interpreter and change in the inline cache type.
- const FldInfoFlags oldflags = dynamicProfileInfo->GetFldInfo(functionBody, inlineCacheIndex)->flags;
- if ((oldflags != FldInfo_NoInfo) &&
- !(oldflags & DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType)))
- {
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
- }
- }
- if (propertyId == Js::PropertyIds::arguments)
- {
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_FromAccessor);
- scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
- }
- if (!Root && operationInfo.isPolymorphic)
- {
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
- }
- fldInfoFlags =
- DynamicProfileInfo::MergeFldInfoFlags(
- fldInfoFlags,
- DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
- fldInfoFlags =
- DynamicProfileInfo::MergeFldInfoFlags(
- fldInfoFlags,
- DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
- if (!Method)
- {
- UpdateFldInfoFlagsForGetSetInlineCandidate(
- object,
- fldInfoFlags,
- operationInfo.cacheType,
- inlineCache,
- functionBody);
- if (!Root && CallApplyTarget)
- {
- UpdateFldInfoFlagsForCallApplyInlineCandidate(
- object,
- fldInfoFlags,
- operationInfo.cacheType,
- inlineCache,
- functionBody);
- }
- }
- }
- else
- {
- Assert(!Root);
- const auto PatchGetValue = &JavascriptOperators::PatchGetValue<false, InlineCache>;
- const auto PatchGetMethod = &JavascriptOperators::PatchGetMethod<false, InlineCache>;
- const auto PatchGet = Method ? PatchGetMethod : PatchGetValue;
- value = PatchGet(functionBody, inlineCache, inlineCacheIndex, instance, propertyId);
- }
- dynamicProfileInfo->RecordFieldAccess(functionBody, inlineCacheIndex, value, fldInfoFlags);
- return value;
- }
- template<bool Root, bool Method, bool CallApplyTarget>
- Var ProfilingHelpers::ProfiledLdFldForTypeOf(
- const Var instance,
- const PropertyId propertyId,
- InlineCache *const inlineCache,
- const InlineCacheIndex inlineCacheIndex,
- FunctionBody *const functionBody)
- {
- Var val = nullptr;
- ScriptContext *scriptContext = functionBody->GetScriptContext();
- BEGIN_PROFILED_TYPEOF_ERROR_HANDLER(scriptContext);
- val = ProfiledLdFld<Root, Method, CallApplyTarget>(
- instance,
- propertyId,
- inlineCache,
- inlineCacheIndex,
- functionBody,
- instance);
- END_PROFILED_TYPEOF_ERROR_HANDLER(scriptContext, val, functionBody, inlineCacheIndex);
- return val;
- }
- void ProfilingHelpers::ProfiledStFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledStFld<false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- PropertyOperation_None,
- scriptFunction,
- instance);
- }
- void ProfilingHelpers::ProfiledStSuperFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer,
- const Var thisInstance)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledStFld<false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- PropertyOperation_None,
- scriptFunction,
- thisInstance);
- }
- void ProfilingHelpers::ProfiledStFld_Strict_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledStFld<false>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- PropertyOperation_StrictMode,
- scriptFunction,
- instance);
- }
- void ProfilingHelpers::ProfiledStRootFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledStFld<true>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- PropertyOperation_Root,
- scriptFunction,
- instance);
- }
- void ProfilingHelpers::ProfiledStRootFld_Strict_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledStFld<true>(
- instance,
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- PropertyOperation_StrictModeRoot,
- scriptFunction,
- instance);
- }
- template<bool Root>
- void ProfilingHelpers::ProfiledStFld(
- const Var instance,
- const PropertyId propertyId,
- InlineCache *const inlineCache,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- const PropertyOperationFlags flags,
- ScriptFunction *const scriptFunction,
- const Var thisInstance)
- {
- Assert(instance);
- Assert(thisInstance);
- Assert(propertyId != Constants::NoProperty);
- Assert(inlineCache);
- Assert(scriptFunction);
- FunctionBody *const functionBody = scriptFunction->GetFunctionBody();
- Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
- Assert(value);
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
- #endif
- ScriptContext *const scriptContext = functionBody->GetScriptContext();
- FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
- if(Root || (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance)))
- {
- RecyclableObject *const object = RecyclableObject::FromVar(instance);
- RecyclableObject *const thisObject = RecyclableObject::FromVar(thisInstance);
- PropertyCacheOperationInfo operationInfo;
- PropertyValueInfo propertyValueInfo;
- PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
- if(!CacheOperators::TrySetProperty<true, true, true, true, !Root, true, false, true>(
- thisObject,
- Root,
- propertyId,
- value,
- scriptContext,
- flags,
- &operationInfo,
- &propertyValueInfo))
- {
- ThreadContext* threadContext = scriptContext->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- Type *const oldType = object->GetType();
- if (Root)
- {
- JavascriptOperators::PatchPutRootValueNoFastPath(functionBody, inlineCache, inlineCacheIndex, object, propertyId, value, flags);
- }
- else
- {
- JavascriptOperators::PatchPutValueWithThisPtrNoFastPath(functionBody, inlineCache, inlineCacheIndex, object, propertyId, value, thisObject, flags);
- }
- CacheOperators::PretendTrySetProperty<true, false>(
- object->GetType(),
- oldType,
- &operationInfo,
- &propertyValueInfo);
- // Setting to __proto__ property invokes a setter and changes the prototype.So, although PatchPut* populates the cache,
- // the setter invalidates it (since it changes the prototype). PretendTrySetProperty looks at the inline cache type to
- // update the cacheType on PropertyOperationInfo, which is used in populating the field info flags for this operation on
- // the profile. Since the cache was invalidated, we don't get a match with either the type of the object with property or
- // without it and the cacheType defaults to CacheType_None. This leads the profile info to say that this operation doesn't
- // cause an accessor implicit call and JIT then doesn't kill live fields across it and ends up putting a BailOutOnImplicitCalls
- // if there were live fields. This bailout always bails out.
- Js::ImplicitCallFlags accessorCallFlag = (Js::ImplicitCallFlags)(Js::ImplicitCall_Accessor & ~Js::ImplicitCall_None);
- if ((threadContext->GetImplicitCallFlags() & accessorCallFlag) != 0)
- {
- operationInfo.cacheType = CacheType_Setter;
- }
- threadContext->SetImplicitCallFlags((Js::ImplicitCallFlags)(savedImplicitCallFlags | threadContext->GetImplicitCallFlags()));
- }
- // Only make the field polymorphic if we are not using the root object inline cache
- if(operationInfo.isPolymorphic && inlineCacheIndex < functionBody->GetRootObjectStoreInlineCacheStart())
- {
- // should not be a load inline cache
- Assert(inlineCacheIndex < functionBody->GetRootObjectLoadInlineCacheStart());
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
- }
- fldInfoFlags =
- DynamicProfileInfo::MergeFldInfoFlags(
- fldInfoFlags,
- DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
- fldInfoFlags =
- DynamicProfileInfo::MergeFldInfoFlags(
- fldInfoFlags,
- DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
- UpdateFldInfoFlagsForGetSetInlineCandidate(
- object,
- fldInfoFlags,
- operationInfo.cacheType,
- inlineCache,
- functionBody);
- if(scriptFunction->GetConstructorCache()->NeedsUpdateAfterCtor())
- {
- // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
- // function object's constructor cache will be updated with the type produced by the constructor. From that
- // point on, when the same function object is used as a constructor, the a new object with the final type will
- // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
- // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
- inlineCache->Clear();
- }
- }
- else
- {
- JavascriptOperators::PatchPutValueNoLocalFastPath<false>(
- functionBody,
- inlineCache,
- inlineCacheIndex,
- instance,
- propertyId,
- value,
- flags);
- }
- functionBody->GetDynamicProfileInfo()->RecordFieldAccess(functionBody, inlineCacheIndex, nullptr, fldInfoFlags);
- }
- void ProfilingHelpers::ProfiledInitFld_Jit(
- const Var instance,
- const PropertyId propertyId,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- void *const framePointer)
- {
- ScriptFunction *const scriptFunction =
- ScriptFunction::FromVar(JavascriptCallStackLayout::FromFramePointer(framePointer)->functionObject);
- ProfiledInitFld(
- RecyclableObject::FromVar(instance),
- propertyId,
- GetInlineCache(scriptFunction, inlineCacheIndex),
- inlineCacheIndex,
- value,
- scriptFunction->GetFunctionBody());
- }
- void ProfilingHelpers::ProfiledInitFld(
- RecyclableObject *const object,
- const PropertyId propertyId,
- InlineCache *const inlineCache,
- const InlineCacheIndex inlineCacheIndex,
- const Var value,
- FunctionBody *const functionBody)
- {
- Assert(object);
- Assert(propertyId != Constants::NoProperty);
- Assert(inlineCache);
- Assert(functionBody);
- Assert(inlineCacheIndex < functionBody->GetInlineCacheCount());
- Assert(value);
- ScriptContext *const scriptContext = functionBody->GetScriptContext();
- FldInfoFlags fldInfoFlags = FldInfo_NoInfo;
- PropertyCacheOperationInfo operationInfo;
- PropertyValueInfo propertyValueInfo;
- PropertyValueInfo::SetCacheInfo(&propertyValueInfo, functionBody, inlineCache, inlineCacheIndex, true);
- if(!CacheOperators::TrySetProperty<true, true, true, true, true, true, false, true>(
- object,
- false,
- propertyId,
- value,
- scriptContext,
- PropertyOperation_None,
- &operationInfo,
- &propertyValueInfo))
- {
- Type *const oldType = object->GetType();
- JavascriptOperators::PatchInitValueNoFastPath(
- functionBody,
- inlineCache,
- inlineCacheIndex,
- object,
- propertyId,
- value);
- CacheOperators::PretendTrySetProperty<true, false>(object->GetType(), oldType, &operationInfo, &propertyValueInfo);
- }
- // Only make the field polymorphic if the we are not using the root object inline cache
- if(operationInfo.isPolymorphic && inlineCacheIndex < functionBody->GetRootObjectStoreInlineCacheStart())
- {
- // should not be a load inline cache
- Assert(inlineCacheIndex < functionBody->GetRootObjectLoadInlineCacheStart());
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_Polymorphic);
- }
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, DynamicProfileInfo::FldInfoFlagsFromCacheType(operationInfo.cacheType));
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, DynamicProfileInfo::FldInfoFlagsFromSlotType(operationInfo.slotType));
- functionBody->GetDynamicProfileInfo()->RecordFieldAccess(functionBody, inlineCacheIndex, nullptr, fldInfoFlags);
- }
- void ProfilingHelpers::UpdateFldInfoFlagsForGetSetInlineCandidate(
- RecyclableObject *const object,
- FldInfoFlags &fldInfoFlags,
- const CacheType cacheType,
- InlineCache *const inlineCache,
- FunctionBody *const functionBody)
- {
- RecyclableObject *callee = nullptr;
- if((cacheType & (CacheType_Getter | CacheType_Setter)) &&
- inlineCache->GetGetterSetter(object->GetType(), &callee))
- {
- const bool canInline = functionBody->GetDynamicProfileInfo()->RecordLdFldCallSiteInfo(functionBody, callee, false /*callApplyTarget*/);
- if(canInline)
- {
- //updates this fldInfoFlags passed by reference.
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
- }
- }
- }
- void ProfilingHelpers::UpdateFldInfoFlagsForCallApplyInlineCandidate(
- RecyclableObject *const object,
- FldInfoFlags &fldInfoFlags,
- const CacheType cacheType,
- InlineCache *const inlineCache,
- FunctionBody *const functionBody)
- {
- RecyclableObject *callee = nullptr;
- if(!(fldInfoFlags & FldInfo_Polymorphic) && inlineCache->GetCallApplyTarget(object, &callee))
- {
- const bool canInline = functionBody->GetDynamicProfileInfo()->RecordLdFldCallSiteInfo(functionBody, callee, true /*callApplyTarget*/);
- if(canInline)
- {
- //updates the fldInfoFlags passed by reference.
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
- }
- }
- }
- InlineCache *ProfilingHelpers::GetInlineCache(ScriptFunction *const scriptFunction, const InlineCacheIndex inlineCacheIndex)
- {
- Assert(scriptFunction);
- Assert(inlineCacheIndex < scriptFunction->GetFunctionBody()->GetInlineCacheCount());
- return
- scriptFunction->GetHasInlineCaches()
- ? ScriptFunctionWithInlineCache::FromVar(scriptFunction)->GetInlineCache(inlineCacheIndex)
- : scriptFunction->GetFunctionBody()->GetInlineCache(inlineCacheIndex);
- }
- #endif
- }
|