| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- namespace Js
- {
- void SimpleJitHelpers::ProfileParameters(void* framePtr)
- {
- auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
- FunctionBody* executeFunction = layout->functionObject->GetFunctionBody();
- const auto dynamicInfo = executeFunction->GetDynamicProfileInfo();
- ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
- AssertMsg(requiredInParamCount > 1, "This function shouldn't be called unless we're expecting to have args to profile!");
- CallInfo callInfo(layout->callInfo);
- Js::ArgumentReader args(&callInfo, layout->args);
- // Ignore the first param. 'this' is profiled as part of LdThis.
- ArgSlot paramIndex = 1;
- const auto maxValid = min((ArgSlot)args.Info.Count, requiredInParamCount);
- for (; paramIndex < maxValid; paramIndex++)
- {
- dynamicInfo->RecordParameterInfo(executeFunction, paramIndex - 1, args[paramIndex]);
- }
- // If they didn't provide enough parameters, record the fact that the rest of the params are undefined.
- if (paramIndex < requiredInParamCount)
- {
- Var varUndef = executeFunction->GetScriptContext()->GetLibrary()->GetUndefined();
- do
- {
- dynamicInfo->RecordParameterInfo(executeFunction, paramIndex - 1, varUndef);
- ++paramIndex;
- } while (paramIndex < requiredInParamCount);
- }
- // Clearing of the implicit call flags is done in jitted code
- }
- void SimpleJitHelpers::CleanImplicitCallFlags(FunctionBody* body)
- {
- // Probably could inline this straight into JITd code.
- auto flags = body->GetScriptContext()->GetThreadContext()->GetImplicitCallFlags();
- body->GetDynamicProfileInfo()->RecordImplicitCallFlags(flags);
- }
- void SimpleJitHelpers::ProfileCall_DefaultInlineCacheIndex(void* framePtr, ProfileId profileId, Var retval, JavascriptFunction* callee, CallInfo info)
- {
- ProfileCall(framePtr, profileId, Constants::NoInlineCacheIndex, retval, callee, info);
- }
- void SimpleJitHelpers::ProfileCall(void* framePtr, ProfileId profileId, InlineCacheIndex inlineCacheIndex, Var retval, Var callee, CallInfo info)
- {
- JavascriptFunction* caller = JavascriptCallStackLayout::FromFramePointer(framePtr)->functionObject;
- FunctionBody* callerFunctionBody = caller->GetFunctionBody();
- DynamicProfileInfo * dynamicProfileInfo = callerFunctionBody->GetDynamicProfileInfo();
- JavascriptFunction *const calleeFunction =
- JavascriptFunction::Is(callee) ? JavascriptFunction::FromVar(callee) : nullptr;
- FunctionInfo* calleeFunctionInfo = calleeFunction ? calleeFunction->GetFunctionInfo() : nullptr;
- auto const ctor = !!(info.Flags & CallFlags_New);
- dynamicProfileInfo->RecordCallSiteInfo(callerFunctionBody, profileId, calleeFunctionInfo, calleeFunction, info.Count, ctor, inlineCacheIndex);
- if (info.Flags & CallFlags_Value)
- {
- dynamicProfileInfo->RecordReturnTypeOnCallSiteInfo(callerFunctionBody, profileId, retval);
- }
- }
- void SimpleJitHelpers::ProfileReturnTypeCall(void* framePtr, ProfileId profileId, Var retval, JavascriptFunction*callee, CallInfo info)
- {
- Assert(info.Flags & CallFlags_Value);
- JavascriptFunction* caller = JavascriptCallStackLayout::FromFramePointer(framePtr)->functionObject;
- FunctionBody* functionBody = caller->GetFunctionBody();
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- dynamicProfileInfo->RecordReturnType(functionBody, profileId, retval);
- }
- Var SimpleJitHelpers::ProfiledLdLen_A(FunctionBody* body, DynamicObject * instance, ProfileId profileId)
- {
- FunctionBody*const functionBody = body;
- const auto profileData = functionBody->GetDynamicProfileInfo();
- LdElemInfo ldElemInfo;
- ldElemInfo.arrayType = ValueType::Uninitialized.Merge(instance);
- Var length = JavascriptOperators::OP_GetProperty(instance, PropertyIds::length, body->GetScriptContext());
- ldElemInfo.elemType = ldElemInfo.elemType.Merge(length);
- profileData->RecordElementLoad(functionBody, profileId, ldElemInfo);
- return length;
- }
- Var SimpleJitHelpers::ProfiledStrictLdThis(Var thisVar, FunctionBody* functionBody)
- {
- //Adapted from InterpreterStackFrame::OP_ProfiledStrictLdThis
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
- if (typeId == TypeIds_ActivationObject)
- {
- thisVar = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
- return thisVar;
- }
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
- return thisVar;
- }
- Var SimpleJitHelpers::ProfiledLdThis(Var thisVar, int moduleID, FunctionBody* functionBody)
- {
- //Adapted from InterpreterStackFrame::OP_ProfiledLdThis
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
- if (JavascriptOperators::IsThisSelf(typeId))
- {
- Assert(typeId != TypeIds_GlobalObject || ((GlobalObject*)thisVar)->ToThis() == thisVar);
- Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
- return thisVar;
- }
- thisVar = JavascriptOperators::OP_GetThis(thisVar, moduleID, functionBody->GetScriptContext());
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
- return thisVar;
- }
- Var SimpleJitHelpers::ProfiledSwitch(FunctionBody* functionBody, ProfileId profileId, Var exp)
- {
- functionBody->GetDynamicProfileInfo()->RecordSwitchType(functionBody, profileId, exp);
- return exp;
- }
- Var SimpleJitHelpers::ProfiledDivide(FunctionBody* functionBody, ProfileId profileId, Var aLeft, Var aRight)
- {
- Var result = JavascriptMath::Divide(aLeft, aRight,functionBody->GetScriptContext());
- functionBody->GetDynamicProfileInfo()->RecordDivideResultType(functionBody, profileId, result);
- return result;
- }
- Var SimpleJitHelpers::ProfiledRemainder(FunctionBody* functionBody, ProfileId profileId, Var aLeft, Var aRight)
- {
- if(TaggedInt::IsPair(aLeft, aRight))
- {
- int nLeft = TaggedInt::ToInt32(aLeft);
- int nRight = TaggedInt::ToInt32(aRight);
- // nLeft is positive and nRight is +2^i
- // Fast path for Power of 2 divisor
- if (nLeft > 0 && ::Math::IsPow2(nRight))
- {
- functionBody->GetDynamicProfileInfo()->RecordModulusOpType(functionBody, profileId, /*isModByPowerOf2*/ true);
- return TaggedInt::ToVarUnchecked(nLeft & (nRight - 1));
- }
- }
- functionBody->GetDynamicProfileInfo()->RecordModulusOpType(functionBody, profileId, /*isModByPowerOf2*/ false);
- return JavascriptMath::Modulus(aLeft, aRight,functionBody->GetScriptContext());
- }
- void SimpleJitHelpers::StoreArrayHelper(Var arr, uint32 index, Var value)
- {
- //Adapted from InterpreterStackFrame::OP_SetArrayItemC_CI4
- JavascriptArray* array = JavascriptArray::FromAnyArray(arr);
- TypeId typeId = array->GetTypeId();
- if (typeId == TypeIds_NativeIntArray)
- {
- JavascriptArray::OP_SetNativeIntElementC(reinterpret_cast<JavascriptNativeIntArray*>(array), index, value, array->GetScriptContext());
- }
- else if (typeId == TypeIds_NativeFloatArray)
- {
- JavascriptArray::OP_SetNativeFloatElementC(reinterpret_cast<JavascriptNativeFloatArray*>(array), index, value, array->GetScriptContext());
- }
- else
- {
- array->SetArrayLiteralItem(index, value);
- }
- }
- void SimpleJitHelpers::StoreArraySegHelper(Var arr, uint32 index, Var value)
- {
- //Adapted from InterpreterStackFrame::OP_SetArraySegmentItem_CI4
- SparseArraySegment<Var> * segment = (SparseArraySegment<Var> *)arr;
- Assert(segment->left == 0);
- Assert(index < segment->length);
- segment->elements[index] = value;
- }
- LoopEntryPointInfo* SimpleJitHelpers::GetScheduledEntryPoint(void* framePtr, uint loopnum)
- {
- auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
- FunctionBody* functionBody = layout->functionObject->GetFunctionBody();
- //REVIEW: Simplejit: Optimization: Don't emit this call if this is true during JIT time
- auto loopHeader = functionBody->GetLoopHeader(loopnum);
- LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
- if (entryPointInfo->IsNotScheduled())
- {
- // Not scheduled yet! It will be impossible for this loop to be scheduled for a JIT unless we're the ones doing it,
- // so there's no need to check whether the existing job is finished.
- return nullptr;
- }
- // The entry point has been scheduled, it is finished, or something else. Just return the entry point and the
- // SimpleJitted function will check this on each iteration.
- return entryPointInfo;
- }
- bool SimpleJitHelpers::IsLoopCodeGenDone(LoopEntryPointInfo* info)
- {
- // It is possible for this work item to be removed from the queue after we found out that it was at some point in the queue.
- // In that case, we must manually increment the interpretCount. Once the work item gets scheduled again, it will trigger
- // a bailout when the threshold is reached.
- if (info->IsNotScheduled())
- {
- ++info->loopHeader->interpretCount;
- return false;
- }
- return info->IsCodeGenDone();
- }
- void SimpleJitHelpers::RecordLoopImplicitCallFlags(void* framePtr, uint loopNum, int restoreCallFlags)
- {
- auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
- FunctionBody* functionBody = layout->functionObject->GetFunctionBody();
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- ThreadContext * threadContext = functionBody->GetScriptContext()->GetThreadContext();
- auto flags = threadContext->GetAddressOfImplicitCallFlags();
- const auto fls = *flags;
- dynamicProfileInfo->RecordLoopImplicitCallFlags(functionBody, loopNum, fls);
- // Due to how JITed code is lowered, even we requested the Opnd to be the size of ImplicitCallArgs, the full
- // register is pushed, with whatever junk is in the upper bits. So mask them off.
- restoreCallFlags = restoreCallFlags & ((1 << sizeof(ImplicitCallFlags)*8) - 1);
- // If the caller doesn't want to add in any call flags they will pass zero in restoreCallFlags.
- // and since ORing with 0 is idempotent, we can just OR it either way
- *flags = (ImplicitCallFlags)(restoreCallFlags | fls);
- }
- }
|