FunctionJITTimeInfo.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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. FunctionJITTimeInfo::FunctionJITTimeInfo(FunctionJITTimeDataIDL * data) : m_data(*data)
  7. {
  8. // we will cast the data (i.e. midl struct) pointers into info pointers so we can extend with methods
  9. CompileAssert(sizeof(FunctionJITTimeDataIDL) == sizeof(FunctionJITTimeInfo));
  10. }
  11. /* static */
  12. void
  13. FunctionJITTimeInfo::BuildJITTimeData(
  14. __in ArenaAllocator * alloc,
  15. __in const Js::FunctionCodeGenJitTimeData * codeGenData,
  16. __in_opt const Js::FunctionCodeGenRuntimeData * runtimeData,
  17. __out FunctionJITTimeDataIDL * jitData,
  18. bool isInlinee,
  19. bool isForegroundJIT)
  20. {
  21. jitData->functionInfoAddr = (intptr_t)codeGenData->GetFunctionInfo();
  22. jitData->localFuncId = codeGenData->GetFunctionInfo()->GetLocalFunctionId();
  23. jitData->isAggressiveInliningEnabled = codeGenData->GetIsAggressiveInliningEnabled();
  24. jitData->isInlined = codeGenData->GetIsInlined();
  25. jitData->weakFuncRef = (intptr_t)codeGenData->GetWeakFuncRef();
  26. jitData->inlineesBv = (BVFixedIDL*)(const BVFixed*)codeGenData->inlineesBv;
  27. if (!codeGenData->GetFunctionBody() || !codeGenData->GetFunctionBody()->GetByteCode())
  28. {
  29. // outermost function must have a body, but inlinees may not (if they are builtins)
  30. Assert(isInlinee);
  31. return;
  32. }
  33. Js::FunctionBody * body = codeGenData->GetFunctionInfo()->GetParseableFunctionInfo()->GetFunctionBody();
  34. jitData->bodyData = AnewStructZ(alloc, FunctionBodyDataIDL);
  35. JITTimeFunctionBody::InitializeJITFunctionData(alloc, body, jitData->bodyData);
  36. Assert(isInlinee == !!runtimeData);
  37. const Js::FunctionCodeGenRuntimeData * targetRuntimeData = nullptr;
  38. if (runtimeData)
  39. {
  40. // may be polymorphic, so seek the runtime data matching our JIT time data
  41. targetRuntimeData = runtimeData->GetForTarget(codeGenData->GetFunctionInfo()->GetFunctionBody());
  42. }
  43. Js::FunctionBody * functionBody = codeGenData->GetFunctionBody();
  44. if (functionBody->HasDynamicProfileInfo())
  45. {
  46. ProfileDataIDL * profileData = AnewStruct(alloc, ProfileDataIDL);
  47. JITTimeProfileInfo::InitializeJITProfileData(alloc, functionBody->GetAnyDynamicProfileInfo(), functionBody, profileData, isForegroundJIT);
  48. jitData->bodyData->profileData = profileData;
  49. if (isInlinee)
  50. {
  51. // if not inlinee, NativeCodeGenerator will provide the address
  52. // REVIEW: OOP JIT, for inlinees, is this actually necessary?
  53. Js::ProxyEntryPointInfo *defaultEntryPointInfo = functionBody->GetDefaultEntryPointInfo();
  54. Assert(defaultEntryPointInfo->IsFunctionEntryPointInfo());
  55. Js::FunctionEntryPointInfo *functionEntryPointInfo = static_cast<Js::FunctionEntryPointInfo*>(defaultEntryPointInfo);
  56. jitData->callsCountAddress = (intptr_t)&functionEntryPointInfo->callsCount;
  57. jitData->sharedPropertyGuards = codeGenData->sharedPropertyGuards;
  58. jitData->sharedPropGuardCount = codeGenData->sharedPropertyGuardCount;
  59. }
  60. }
  61. if (jitData->bodyData->profiledCallSiteCount > 0)
  62. {
  63. jitData->inlineeCount = jitData->bodyData->profiledCallSiteCount;
  64. // using arena because we can't recycler allocate (may be on background), and heap freeing this is slightly complicated
  65. jitData->inlinees = AnewArrayZ(alloc, FunctionJITTimeDataIDL*, jitData->bodyData->profiledCallSiteCount);
  66. jitData->inlineesRecursionFlags = AnewArrayZ(alloc, boolean, jitData->bodyData->profiledCallSiteCount);
  67. for (Js::ProfileId i = 0; i < jitData->bodyData->profiledCallSiteCount; ++i)
  68. {
  69. const Js::FunctionCodeGenJitTimeData * inlineeJITData = codeGenData->GetInlinee(i);
  70. if (inlineeJITData == codeGenData)
  71. {
  72. jitData->inlineesRecursionFlags[i] = TRUE;
  73. }
  74. else if (inlineeJITData != nullptr)
  75. {
  76. const Js::FunctionCodeGenRuntimeData * inlineeRuntimeData = nullptr;
  77. if (inlineeJITData->GetFunctionInfo()->HasBody())
  78. {
  79. inlineeRuntimeData = isInlinee ? targetRuntimeData->GetInlinee(i) : functionBody->GetInlineeCodeGenRuntimeData(i);
  80. }
  81. jitData->inlinees[i] = AnewStructZ(alloc, FunctionJITTimeDataIDL);
  82. BuildJITTimeData(alloc, inlineeJITData, inlineeRuntimeData, jitData->inlinees[i], true, isForegroundJIT);
  83. }
  84. }
  85. }
  86. jitData->profiledRuntimeData = AnewStructZ(alloc, FunctionJITRuntimeIDL);
  87. if (isInlinee && targetRuntimeData->ClonedInlineCaches()->HasInlineCaches())
  88. {
  89. jitData->profiledRuntimeData->clonedCacheCount = jitData->bodyData->inlineCacheCount;
  90. jitData->profiledRuntimeData->clonedInlineCaches = AnewArray(alloc, intptr_t, jitData->profiledRuntimeData->clonedCacheCount);
  91. for (uint j = 0; j < jitData->bodyData->inlineCacheCount; ++j)
  92. {
  93. jitData->profiledRuntimeData->clonedInlineCaches[j] = (intptr_t)targetRuntimeData->ClonedInlineCaches()->GetInlineCache(j);
  94. }
  95. }
  96. if (jitData->bodyData->inlineCacheCount > 0)
  97. {
  98. jitData->ldFldInlineeCount = jitData->bodyData->inlineCacheCount;
  99. jitData->ldFldInlinees = AnewArrayZ(alloc, FunctionJITTimeDataIDL*, jitData->bodyData->inlineCacheCount);
  100. Field(ObjTypeSpecFldInfo*)* objTypeSpecInfo = codeGenData->GetObjTypeSpecFldInfoArray()->GetInfoArray();
  101. if(objTypeSpecInfo)
  102. {
  103. jitData->objTypeSpecFldInfoCount = jitData->bodyData->inlineCacheCount;
  104. jitData->objTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)objTypeSpecInfo;
  105. }
  106. for (Js::InlineCacheIndex i = 0; i < jitData->bodyData->inlineCacheCount; ++i)
  107. {
  108. const Js::FunctionCodeGenJitTimeData * inlineeJITData = codeGenData->GetLdFldInlinee(i);
  109. const Js::FunctionCodeGenRuntimeData * inlineeRuntimeData = isInlinee ? targetRuntimeData->GetLdFldInlinee(i) : functionBody->GetLdFldInlineeCodeGenRuntimeData(i);
  110. if (inlineeJITData != nullptr)
  111. {
  112. jitData->ldFldInlinees[i] = AnewStructZ(alloc, FunctionJITTimeDataIDL);
  113. BuildJITTimeData(alloc, inlineeJITData, inlineeRuntimeData, jitData->ldFldInlinees[i], true, isForegroundJIT);
  114. }
  115. }
  116. }
  117. if (!isInlinee && codeGenData->GetGlobalObjTypeSpecFldInfoCount() > 0)
  118. {
  119. Field(ObjTypeSpecFldInfo*)* globObjTypeSpecInfo = codeGenData->GetGlobalObjTypeSpecFldInfoArray();
  120. Assert(globObjTypeSpecInfo != nullptr);
  121. jitData->globalObjTypeSpecFldInfoCount = codeGenData->GetGlobalObjTypeSpecFldInfoCount();
  122. jitData->globalObjTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)globObjTypeSpecInfo;
  123. }
  124. const Js::FunctionCodeGenJitTimeData * nextJITData = codeGenData->GetNext();
  125. if (nextJITData != nullptr)
  126. {
  127. // only inlinee should be polymorphic
  128. Assert(isInlinee);
  129. jitData->next = AnewStructZ(alloc, FunctionJITTimeDataIDL);
  130. BuildJITTimeData(alloc, nextJITData, runtimeData, jitData->next, true, isForegroundJIT);
  131. }
  132. }
  133. uint
  134. FunctionJITTimeInfo::GetInlineeCount() const
  135. {
  136. return m_data.inlineeCount;
  137. }
  138. bool
  139. FunctionJITTimeInfo::IsLdFldInlineePresent() const
  140. {
  141. return m_data.ldFldInlineeCount != 0;
  142. }
  143. bool
  144. FunctionJITTimeInfo::HasSharedPropertyGuards() const
  145. {
  146. return m_data.sharedPropGuardCount != 0;
  147. }
  148. bool
  149. FunctionJITTimeInfo::HasSharedPropertyGuard(Js::PropertyId id) const
  150. {
  151. for (uint i = 0; i < m_data.sharedPropGuardCount; ++i)
  152. {
  153. if (m_data.sharedPropertyGuards[i] == id)
  154. {
  155. return true;
  156. }
  157. }
  158. return false;
  159. }
  160. intptr_t
  161. FunctionJITTimeInfo::GetFunctionInfoAddr() const
  162. {
  163. return m_data.functionInfoAddr;
  164. }
  165. intptr_t
  166. FunctionJITTimeInfo::GetWeakFuncRef() const
  167. {
  168. return m_data.weakFuncRef;
  169. }
  170. uint
  171. FunctionJITTimeInfo::GetLocalFunctionId() const
  172. {
  173. return m_data.localFuncId;
  174. }
  175. bool
  176. FunctionJITTimeInfo::IsAggressiveInliningEnabled() const
  177. {
  178. return m_data.isAggressiveInliningEnabled != FALSE;
  179. }
  180. bool
  181. FunctionJITTimeInfo::IsInlined() const
  182. {
  183. return m_data.isInlined != FALSE;
  184. }
  185. const BVFixed *
  186. FunctionJITTimeInfo::GetInlineesBV() const
  187. {
  188. return reinterpret_cast<const BVFixed *>(m_data.inlineesBv);
  189. }
  190. const FunctionJITTimeInfo *
  191. FunctionJITTimeInfo::GetJitTimeDataFromFunctionInfoAddr(intptr_t polyFuncInfo) const
  192. {
  193. const FunctionJITTimeInfo *next = this;
  194. while (next && next->GetFunctionInfoAddr() != polyFuncInfo)
  195. {
  196. next = next->GetNext();
  197. }
  198. return next;
  199. }
  200. const FunctionJITRuntimeInfo *
  201. FunctionJITTimeInfo::GetInlineeForTargetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId, intptr_t inlineeFuncBodyAddr) const
  202. {
  203. const FunctionJITTimeInfo *inlineeData = GetInlinee(profiledCallSiteId);
  204. while (inlineeData && inlineeData->GetBody()->GetAddr() != inlineeFuncBodyAddr)
  205. {
  206. inlineeData = inlineeData->GetNext();
  207. }
  208. __analysis_assume(inlineeData != nullptr);
  209. return inlineeData->GetRuntimeInfo();
  210. }
  211. const FunctionJITRuntimeInfo *
  212. FunctionJITTimeInfo::GetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId) const
  213. {
  214. return GetInlinee(profiledCallSiteId) ? GetInlinee(profiledCallSiteId)->GetRuntimeInfo() : nullptr;
  215. }
  216. const FunctionJITRuntimeInfo *
  217. FunctionJITTimeInfo::GetLdFldInlineeRuntimeData(const Js::InlineCacheIndex inlineCacheIndex) const
  218. {
  219. return GetLdFldInlinee(inlineCacheIndex) ? GetLdFldInlinee(inlineCacheIndex)->GetRuntimeInfo() : nullptr;
  220. }
  221. const FunctionJITRuntimeInfo *
  222. FunctionJITTimeInfo::GetRuntimeInfo() const
  223. {
  224. return reinterpret_cast<const FunctionJITRuntimeInfo*>(m_data.profiledRuntimeData);
  225. }
  226. ObjTypeSpecFldInfo *
  227. FunctionJITTimeInfo::GetObjTypeSpecFldInfo(uint index) const
  228. {
  229. Assert(index < GetBody()->GetInlineCacheCount());
  230. if (m_data.objTypeSpecFldInfoArray == nullptr)
  231. {
  232. return nullptr;
  233. }
  234. return reinterpret_cast<ObjTypeSpecFldInfo *>(m_data.objTypeSpecFldInfoArray[index]);
  235. }
  236. ObjTypeSpecFldInfo *
  237. FunctionJITTimeInfo::GetGlobalObjTypeSpecFldInfo(uint index) const
  238. {
  239. Assert(index < m_data.globalObjTypeSpecFldInfoCount);
  240. return reinterpret_cast<ObjTypeSpecFldInfo *>(m_data.globalObjTypeSpecFldInfoArray[index]);
  241. }
  242. uint
  243. FunctionJITTimeInfo::GetGlobalObjTypeSpecFldInfoCount() const
  244. {
  245. return m_data.globalObjTypeSpecFldInfoCount;
  246. }
  247. uint
  248. FunctionJITTimeInfo::GetSourceContextId() const
  249. {
  250. Assert(HasBody());
  251. return GetBody()->GetSourceContextId();
  252. }
  253. const FunctionJITTimeInfo *
  254. FunctionJITTimeInfo::GetLdFldInlinee(Js::InlineCacheIndex inlineCacheIndex) const
  255. {
  256. Assert(inlineCacheIndex < m_data.bodyData->inlineCacheCount);
  257. if (!m_data.ldFldInlinees)
  258. {
  259. return nullptr;
  260. }
  261. Assert(inlineCacheIndex < m_data.ldFldInlineeCount);
  262. return reinterpret_cast<const FunctionJITTimeInfo*>(m_data.ldFldInlinees[inlineCacheIndex]);
  263. }
  264. const FunctionJITTimeInfo *
  265. FunctionJITTimeInfo::GetInlinee(Js::ProfileId profileId) const
  266. {
  267. Assert(profileId < m_data.bodyData->profiledCallSiteCount);
  268. if (!m_data.inlinees)
  269. {
  270. return nullptr;
  271. }
  272. Assert(profileId < m_data.inlineeCount);
  273. auto inlinee = reinterpret_cast<const FunctionJITTimeInfo *>(m_data.inlinees[profileId]);
  274. if (inlinee == nullptr && m_data.inlineesRecursionFlags[profileId])
  275. {
  276. inlinee = this;
  277. }
  278. return inlinee;
  279. }
  280. const FunctionJITTimeInfo *
  281. FunctionJITTimeInfo::GetNext() const
  282. {
  283. return reinterpret_cast<const FunctionJITTimeInfo *>(m_data.next);
  284. }
  285. JITTimeFunctionBody *
  286. FunctionJITTimeInfo::GetBody() const
  287. {
  288. return reinterpret_cast<JITTimeFunctionBody *>(m_data.bodyData);
  289. }
  290. bool
  291. FunctionJITTimeInfo::HasBody() const
  292. {
  293. return m_data.bodyData != nullptr;
  294. }
  295. bool
  296. FunctionJITTimeInfo::IsPolymorphicCallSite(Js::ProfileId profiledCallSiteId) const
  297. {
  298. Assert(profiledCallSiteId < m_data.bodyData->profiledCallSiteCount);
  299. if (!m_data.inlinees)
  300. {
  301. return false;
  302. }
  303. Assert(profiledCallSiteId < m_data.inlineeCount);
  304. return ((FunctionJITTimeDataIDL*)this->GetInlinee(profiledCallSiteId))->next != nullptr;
  305. }
  306. bool
  307. FunctionJITTimeInfo::ForceJITLoopBody() const
  308. {
  309. return
  310. !PHASE_OFF(Js::JITLoopBodyPhase, this) &&
  311. !PHASE_OFF(Js::FullJitPhase, this) &&
  312. !GetBody()->IsGenerator() &&
  313. !GetBody()->HasTry() &&
  314. (
  315. PHASE_FORCE(Js::JITLoopBodyPhase, this)
  316. #ifdef ENABLE_PREJIT
  317. || Js::Configuration::Global.flags.Prejit
  318. #endif
  319. );
  320. }
  321. char16*
  322. FunctionJITTimeInfo::GetDisplayName() const
  323. {
  324. return GetBody()->GetDisplayName();
  325. }
  326. char16*
  327. FunctionJITTimeInfo::GetDebugNumberSet(wchar(&bufferToWriteTo)[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]) const
  328. {
  329. // (#%u.%u), #%u --> (source file Id . function Id) , function Number
  330. int len = swprintf_s(bufferToWriteTo, MAX_FUNCTION_BODY_DEBUG_STRING_SIZE, _u(" (#%d.%u), #%u"),
  331. (int)GetSourceContextId(), GetLocalFunctionId(), GetBody()->GetFunctionNumber());
  332. Assert(len > 8);
  333. return bufferToWriteTo;
  334. }