SimpleJitProfilingHelpers.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 "BackEnd.h"
  6. namespace Js
  7. {
  8. void SimpleJitHelpers::ProfileParameters(void* framePtr)
  9. {
  10. auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
  11. FunctionBody* executeFunction = layout->functionObject->GetFunctionBody();
  12. const auto dynamicInfo = executeFunction->GetDynamicProfileInfo();
  13. ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
  14. AssertMsg(requiredInParamCount > 1, "This function shouldn't be called unless we're expecting to have args to profile!");
  15. CallInfo callInfo(layout->callInfo);
  16. Js::ArgumentReader args(&callInfo, layout->args);
  17. // Ignore the first param. 'this' is profiled as part of LdThis.
  18. ArgSlot paramIndex = 1;
  19. const auto maxValid = min((ArgSlot)args.Info.Count, requiredInParamCount);
  20. for (; paramIndex < maxValid; paramIndex++)
  21. {
  22. dynamicInfo->RecordParameterInfo(executeFunction, paramIndex - 1, args[paramIndex]);
  23. }
  24. // If they didn't provide enough parameters, record the fact that the rest of the params are undefined.
  25. if (paramIndex < requiredInParamCount)
  26. {
  27. Var varUndef = executeFunction->GetScriptContext()->GetLibrary()->GetUndefined();
  28. do
  29. {
  30. dynamicInfo->RecordParameterInfo(executeFunction, paramIndex - 1, varUndef);
  31. ++paramIndex;
  32. } while (paramIndex < requiredInParamCount);
  33. }
  34. // Clearing of the implicit call flags is done in jitted code
  35. }
  36. void SimpleJitHelpers::CleanImplicitCallFlags(FunctionBody* body)
  37. {
  38. // Probably could inline this straight into JITd code.
  39. auto flags = body->GetScriptContext()->GetThreadContext()->GetImplicitCallFlags();
  40. body->GetDynamicProfileInfo()->RecordImplicitCallFlags(flags);
  41. }
  42. void SimpleJitHelpers::ProfileCall_DefaultInlineCacheIndex(void* framePtr, ProfileId profileId, Var retval, JavascriptFunction* callee, CallInfo info)
  43. {
  44. ProfileCall(framePtr, profileId, Constants::NoInlineCacheIndex, retval, callee, info);
  45. }
  46. void SimpleJitHelpers::ProfileCall(void* framePtr, ProfileId profileId, InlineCacheIndex inlineCacheIndex, Var retval, Var callee, CallInfo info)
  47. {
  48. JavascriptFunction* caller = JavascriptCallStackLayout::FromFramePointer(framePtr)->functionObject;
  49. FunctionBody* callerFunctionBody = caller->GetFunctionBody();
  50. DynamicProfileInfo * dynamicProfileInfo = callerFunctionBody->GetDynamicProfileInfo();
  51. JavascriptFunction *const calleeFunction =
  52. JavascriptFunction::Is(callee) ? JavascriptFunction::FromVar(callee) : nullptr;
  53. FunctionInfo* calleeFunctionInfo = calleeFunction ? calleeFunction->GetFunctionInfo() : nullptr;
  54. auto const ctor = !!(info.Flags & CallFlags_New);
  55. dynamicProfileInfo->RecordCallSiteInfo(callerFunctionBody, profileId, calleeFunctionInfo, calleeFunction, info.Count, ctor, inlineCacheIndex);
  56. if (info.Flags & CallFlags_Value)
  57. {
  58. dynamicProfileInfo->RecordReturnTypeOnCallSiteInfo(callerFunctionBody, profileId, retval);
  59. }
  60. }
  61. void SimpleJitHelpers::ProfileReturnTypeCall(void* framePtr, ProfileId profileId, Var retval, JavascriptFunction*callee, CallInfo info)
  62. {
  63. Assert(info.Flags & CallFlags_Value);
  64. JavascriptFunction* caller = JavascriptCallStackLayout::FromFramePointer(framePtr)->functionObject;
  65. FunctionBody* functionBody = caller->GetFunctionBody();
  66. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  67. dynamicProfileInfo->RecordReturnType(functionBody, profileId, retval);
  68. }
  69. Var SimpleJitHelpers::ProfiledLdLen_A(FunctionBody* body, DynamicObject * instance, ProfileId profileId)
  70. {
  71. FunctionBody*const functionBody = body;
  72. const auto profileData = functionBody->GetDynamicProfileInfo();
  73. LdElemInfo ldElemInfo;
  74. ldElemInfo.arrayType = ValueType::Uninitialized.Merge(instance);
  75. Var length = JavascriptOperators::OP_GetProperty(instance, PropertyIds::length, body->GetScriptContext());
  76. ldElemInfo.elemType = ldElemInfo.elemType.Merge(length);
  77. profileData->RecordElementLoad(functionBody, profileId, ldElemInfo);
  78. return length;
  79. }
  80. Var SimpleJitHelpers::ProfiledStrictLdThis(Var thisVar, FunctionBody* functionBody)
  81. {
  82. //Adapted from InterpreterStackFrame::OP_ProfiledStrictLdThis
  83. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  84. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  85. if (typeId == TypeIds_ActivationObject)
  86. {
  87. thisVar = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
  88. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  89. return thisVar;
  90. }
  91. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  92. return thisVar;
  93. }
  94. Var SimpleJitHelpers::ProfiledLdThis(Var thisVar, int moduleID, FunctionBody* functionBody)
  95. {
  96. //Adapted from InterpreterStackFrame::OP_ProfiledLdThis
  97. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  98. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  99. if (JavascriptOperators::IsThisSelf(typeId))
  100. {
  101. Assert(typeId != TypeIds_GlobalObject || ((GlobalObject*)thisVar)->ToThis() == thisVar);
  102. Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
  103. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  104. return thisVar;
  105. }
  106. thisVar = JavascriptOperators::OP_GetThis(thisVar, moduleID, functionBody->GetScriptContext());
  107. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  108. return thisVar;
  109. }
  110. Var SimpleJitHelpers::ProfiledSwitch(FunctionBody* functionBody, ProfileId profileId, Var exp)
  111. {
  112. functionBody->GetDynamicProfileInfo()->RecordSwitchType(functionBody, profileId, exp);
  113. return exp;
  114. }
  115. Var SimpleJitHelpers::ProfiledDivide(FunctionBody* functionBody, ProfileId profileId, Var aLeft, Var aRight)
  116. {
  117. Var result = JavascriptMath::Divide(aLeft, aRight,functionBody->GetScriptContext());
  118. functionBody->GetDynamicProfileInfo()->RecordDivideResultType(functionBody, profileId, result);
  119. return result;
  120. }
  121. Var SimpleJitHelpers::ProfiledRemainder(FunctionBody* functionBody, ProfileId profileId, Var aLeft, Var aRight)
  122. {
  123. if(TaggedInt::IsPair(aLeft, aRight))
  124. {
  125. int nLeft = TaggedInt::ToInt32(aLeft);
  126. int nRight = TaggedInt::ToInt32(aRight);
  127. // nLeft is positive and nRight is +2^i
  128. // Fast path for Power of 2 divisor
  129. if (nLeft > 0 && ::Math::IsPow2(nRight))
  130. {
  131. functionBody->GetDynamicProfileInfo()->RecordModulusOpType(functionBody, profileId, /*isModByPowerOf2*/ true);
  132. return TaggedInt::ToVarUnchecked(nLeft & (nRight - 1));
  133. }
  134. }
  135. functionBody->GetDynamicProfileInfo()->RecordModulusOpType(functionBody, profileId, /*isModByPowerOf2*/ false);
  136. return JavascriptMath::Modulus(aLeft, aRight,functionBody->GetScriptContext());
  137. }
  138. void SimpleJitHelpers::StoreArrayHelper(Var arr, uint32 index, Var value)
  139. {
  140. //Adapted from InterpreterStackFrame::OP_SetArrayItemC_CI4
  141. JavascriptArray* array = JavascriptArray::FromAnyArray(arr);
  142. TypeId typeId = array->GetTypeId();
  143. if (typeId == TypeIds_NativeIntArray)
  144. {
  145. JavascriptArray::OP_SetNativeIntElementC(reinterpret_cast<JavascriptNativeIntArray*>(array), index, value, array->GetScriptContext());
  146. }
  147. else if (typeId == TypeIds_NativeFloatArray)
  148. {
  149. JavascriptArray::OP_SetNativeFloatElementC(reinterpret_cast<JavascriptNativeFloatArray*>(array), index, value, array->GetScriptContext());
  150. }
  151. else
  152. {
  153. array->SetArrayLiteralItem(index, value);
  154. }
  155. }
  156. void SimpleJitHelpers::StoreArraySegHelper(Var arr, uint32 index, Var value)
  157. {
  158. //Adapted from InterpreterStackFrame::OP_SetArraySegmentItem_CI4
  159. SparseArraySegment<Var> * segment = (SparseArraySegment<Var> *)arr;
  160. Assert(segment->left == 0);
  161. Assert(index < segment->length);
  162. segment->elements[index] = value;
  163. }
  164. LoopEntryPointInfo* SimpleJitHelpers::GetScheduledEntryPoint(void* framePtr, uint loopnum)
  165. {
  166. auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
  167. FunctionBody* functionBody = layout->functionObject->GetFunctionBody();
  168. //REVIEW: Simplejit: Optimization: Don't emit this call if this is true during JIT time
  169. auto loopHeader = functionBody->GetLoopHeader(loopnum);
  170. LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
  171. if (entryPointInfo->IsNotScheduled())
  172. {
  173. // Not scheduled yet! It will be impossible for this loop to be scheduled for a JIT unless we're the ones doing it,
  174. // so there's no need to check whether the existing job is finished.
  175. return nullptr;
  176. }
  177. // The entry point has been scheduled, it is finished, or something else. Just return the entry point and the
  178. // SimpleJitted function will check this on each iteration.
  179. return entryPointInfo;
  180. }
  181. bool SimpleJitHelpers::IsLoopCodeGenDone(LoopEntryPointInfo* info)
  182. {
  183. // 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.
  184. // In that case, we must manually increment the interpretCount. Once the work item gets scheduled again, it will trigger
  185. // a bailout when the threshold is reached.
  186. if (info->IsNotScheduled())
  187. {
  188. ++info->loopHeader->interpretCount;
  189. return false;
  190. }
  191. return info->IsCodeGenDone();
  192. }
  193. void SimpleJitHelpers::RecordLoopImplicitCallFlags(void* framePtr, uint loopNum, int restoreCallFlags)
  194. {
  195. auto layout = JavascriptCallStackLayout::FromFramePointer(framePtr);
  196. FunctionBody* functionBody = layout->functionObject->GetFunctionBody();
  197. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  198. ThreadContext * threadContext = functionBody->GetScriptContext()->GetThreadContext();
  199. auto flags = threadContext->GetAddressOfImplicitCallFlags();
  200. const auto fls = *flags;
  201. dynamicProfileInfo->RecordLoopImplicitCallFlags(functionBody, loopNum, fls);
  202. // Due to how JITed code is lowered, even we requested the Opnd to be the size of ImplicitCallArgs, the full
  203. // register is pushed, with whatever junk is in the upper bits. So mask them off.
  204. restoreCallFlags = restoreCallFlags & ((1 << sizeof(ImplicitCallFlags)*8) - 1);
  205. // If the caller doesn't want to add in any call flags they will pass zero in restoreCallFlags.
  206. // and since ORing with 0 is idempotent, we can just OR it either way
  207. *flags = (ImplicitCallFlags)(restoreCallFlags | fls);
  208. }
  209. }