FunctionJITTimeInfo.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. if (codeGenData->GetFunctionBody() && codeGenData->GetFunctionBody()->GetByteCode())
  23. {
  24. Js::FunctionBody * body = codeGenData->GetFunctionInfo()->GetParseableFunctionInfo()->GetFunctionBody();
  25. jitData->bodyData = AnewStructZ(alloc, FunctionBodyDataIDL);
  26. JITTimeFunctionBody::InitializeJITFunctionData(alloc, body, jitData->bodyData);
  27. }
  28. jitData->localFuncId = codeGenData->GetFunctionInfo()->GetLocalFunctionId();
  29. jitData->isAggressiveInliningEnabled = codeGenData->GetIsAggressiveInliningEnabled();
  30. jitData->isInlined = codeGenData->GetIsInlined();
  31. jitData->weakFuncRef = (intptr_t)codeGenData->GetWeakFuncRef();
  32. jitData->inlineesBv = (BVFixedIDL*)(const BVFixed*)codeGenData->inlineesBv;
  33. if (codeGenData->GetFunctionInfo()->HasBody() && codeGenData->GetFunctionInfo()->GetFunctionProxy()->IsFunctionBody())
  34. {
  35. Assert(isInlinee == !!runtimeData);
  36. const Js::FunctionCodeGenRuntimeData * targetRuntimeData = nullptr;
  37. if (runtimeData)
  38. {
  39. // may be polymorphic, so seek the runtime data matching our JIT time data
  40. targetRuntimeData = runtimeData->GetForTarget(codeGenData->GetFunctionInfo()->GetFunctionBody());
  41. }
  42. Js::FunctionBody * functionBody = codeGenData->GetFunctionBody();
  43. if (functionBody->HasDynamicProfileInfo())
  44. {
  45. Assert(jitData->bodyData != nullptr);
  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(Js::ObjTypeSpecFldInfo*)* objTypeSpecInfo = codeGenData->GetObjTypeSpecFldInfoArray()->GetInfoArray();
  101. if(objTypeSpecInfo)
  102. {
  103. jitData->objTypeSpecFldInfoCount = jitData->bodyData->inlineCacheCount;
  104. jitData->objTypeSpecFldInfoArray = AnewArrayZ(alloc, ObjTypeSpecFldIDL, jitData->bodyData->inlineCacheCount);
  105. JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(alloc, objTypeSpecInfo, jitData->objTypeSpecFldInfoCount, jitData->objTypeSpecFldInfoArray);
  106. }
  107. for (Js::InlineCacheIndex i = 0; i < jitData->bodyData->inlineCacheCount; ++i)
  108. {
  109. const Js::FunctionCodeGenJitTimeData * inlineeJITData = codeGenData->GetLdFldInlinee(i);
  110. const Js::FunctionCodeGenRuntimeData * inlineeRuntimeData = isInlinee ? targetRuntimeData->GetLdFldInlinee(i) : functionBody->GetLdFldInlineeCodeGenRuntimeData(i);
  111. if (inlineeJITData != nullptr)
  112. {
  113. jitData->ldFldInlinees[i] = AnewStructZ(alloc, FunctionJITTimeDataIDL);
  114. BuildJITTimeData(alloc, inlineeJITData, inlineeRuntimeData, jitData->ldFldInlinees[i], true, isForegroundJIT);
  115. }
  116. }
  117. }
  118. if (!isInlinee && codeGenData->GetGlobalObjTypeSpecFldInfoCount() > 0)
  119. {
  120. Field(Js::ObjTypeSpecFldInfo*)* globObjTypeSpecInfo = codeGenData->GetGlobalObjTypeSpecFldInfoArray();
  121. Assert(globObjTypeSpecInfo != nullptr);
  122. jitData->globalObjTypeSpecFldInfoCount = codeGenData->GetGlobalObjTypeSpecFldInfoCount();
  123. jitData->globalObjTypeSpecFldInfoArray = AnewArrayZ(alloc, ObjTypeSpecFldIDL, jitData->globalObjTypeSpecFldInfoCount);
  124. JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(alloc, globObjTypeSpecInfo, jitData->globalObjTypeSpecFldInfoCount, jitData->globalObjTypeSpecFldInfoArray);
  125. }
  126. const Js::FunctionCodeGenJitTimeData * nextJITData = codeGenData->GetNext();
  127. if (nextJITData != nullptr)
  128. {
  129. // only inlinee should be polymorphic
  130. Assert(isInlinee);
  131. jitData->next = AnewStructZ(alloc, FunctionJITTimeDataIDL);
  132. BuildJITTimeData(alloc, nextJITData, runtimeData, jitData->next, true, isForegroundJIT);
  133. }
  134. }
  135. }
  136. uint
  137. FunctionJITTimeInfo::GetInlineeCount() const
  138. {
  139. return m_data.inlineeCount;
  140. }
  141. bool
  142. FunctionJITTimeInfo::IsLdFldInlineePresent() const
  143. {
  144. return m_data.ldFldInlineeCount != 0;
  145. }
  146. bool
  147. FunctionJITTimeInfo::HasSharedPropertyGuards() const
  148. {
  149. return m_data.sharedPropGuardCount != 0;
  150. }
  151. bool
  152. FunctionJITTimeInfo::HasSharedPropertyGuard(Js::PropertyId id) const
  153. {
  154. for (uint i = 0; i < m_data.sharedPropGuardCount; ++i)
  155. {
  156. if (m_data.sharedPropertyGuards[i] == id)
  157. {
  158. return true;
  159. }
  160. }
  161. return false;
  162. }
  163. intptr_t
  164. FunctionJITTimeInfo::GetFunctionInfoAddr() const
  165. {
  166. return m_data.functionInfoAddr;
  167. }
  168. intptr_t
  169. FunctionJITTimeInfo::GetWeakFuncRef() const
  170. {
  171. return m_data.weakFuncRef;
  172. }
  173. uint
  174. FunctionJITTimeInfo::GetLocalFunctionId() const
  175. {
  176. return m_data.localFuncId;
  177. }
  178. bool
  179. FunctionJITTimeInfo::IsAggressiveInliningEnabled() const
  180. {
  181. return m_data.isAggressiveInliningEnabled != FALSE;
  182. }
  183. bool
  184. FunctionJITTimeInfo::IsInlined() const
  185. {
  186. return m_data.isInlined != FALSE;
  187. }
  188. const BVFixed *
  189. FunctionJITTimeInfo::GetInlineesBV() const
  190. {
  191. return reinterpret_cast<const BVFixed *>(m_data.inlineesBv);
  192. }
  193. const FunctionJITTimeInfo *
  194. FunctionJITTimeInfo::GetJitTimeDataFromFunctionInfoAddr(intptr_t polyFuncInfo) const
  195. {
  196. const FunctionJITTimeInfo *next = this;
  197. while (next && next->GetFunctionInfoAddr() != polyFuncInfo)
  198. {
  199. next = next->GetNext();
  200. }
  201. return next;
  202. }
  203. const FunctionJITRuntimeInfo *
  204. FunctionJITTimeInfo::GetInlineeForTargetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId, intptr_t inlineeFuncBodyAddr) const
  205. {
  206. const FunctionJITTimeInfo *inlineeData = GetInlinee(profiledCallSiteId);
  207. while (inlineeData && inlineeData->GetBody()->GetAddr() != inlineeFuncBodyAddr)
  208. {
  209. inlineeData = inlineeData->GetNext();
  210. }
  211. __analysis_assume(inlineeData != nullptr);
  212. return inlineeData->GetRuntimeInfo();
  213. }
  214. const FunctionJITRuntimeInfo *
  215. FunctionJITTimeInfo::GetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId) const
  216. {
  217. return GetInlinee(profiledCallSiteId) ? GetInlinee(profiledCallSiteId)->GetRuntimeInfo() : nullptr;
  218. }
  219. const FunctionJITRuntimeInfo *
  220. FunctionJITTimeInfo::GetLdFldInlineeRuntimeData(const Js::InlineCacheIndex inlineCacheIndex) const
  221. {
  222. return GetLdFldInlinee(inlineCacheIndex) ? GetLdFldInlinee(inlineCacheIndex)->GetRuntimeInfo() : nullptr;
  223. }
  224. const FunctionJITRuntimeInfo *
  225. FunctionJITTimeInfo::GetRuntimeInfo() const
  226. {
  227. return reinterpret_cast<const FunctionJITRuntimeInfo*>(m_data.profiledRuntimeData);
  228. }
  229. JITObjTypeSpecFldInfo *
  230. FunctionJITTimeInfo::GetObjTypeSpecFldInfo(uint index) const
  231. {
  232. Assert(index < GetBody()->GetInlineCacheCount());
  233. if (m_data.objTypeSpecFldInfoArray == nullptr)
  234. {
  235. return nullptr;
  236. }
  237. if (!m_data.objTypeSpecFldInfoArray[index].inUse)
  238. {
  239. return nullptr;
  240. }
  241. return reinterpret_cast<JITObjTypeSpecFldInfo *>(&m_data.objTypeSpecFldInfoArray[index]);
  242. }
  243. JITObjTypeSpecFldInfo *
  244. FunctionJITTimeInfo::GetGlobalObjTypeSpecFldInfo(uint index) const
  245. {
  246. Assert(index < m_data.globalObjTypeSpecFldInfoCount);
  247. if (!m_data.globalObjTypeSpecFldInfoArray[index].inUse)
  248. {
  249. return nullptr;
  250. }
  251. return reinterpret_cast<JITObjTypeSpecFldInfo *>(&m_data.globalObjTypeSpecFldInfoArray[index]);
  252. }
  253. uint
  254. FunctionJITTimeInfo::GetGlobalObjTypeSpecFldInfoCount() const
  255. {
  256. return m_data.globalObjTypeSpecFldInfoCount;
  257. }
  258. uint
  259. FunctionJITTimeInfo::GetSourceContextId() const
  260. {
  261. Assert(HasBody());
  262. return GetBody()->GetSourceContextId();
  263. }
  264. const FunctionJITTimeInfo *
  265. FunctionJITTimeInfo::GetLdFldInlinee(Js::InlineCacheIndex inlineCacheIndex) const
  266. {
  267. Assert(inlineCacheIndex < m_data.bodyData->inlineCacheCount);
  268. if (!m_data.ldFldInlinees)
  269. {
  270. return nullptr;
  271. }
  272. Assert(inlineCacheIndex < m_data.ldFldInlineeCount);
  273. return reinterpret_cast<const FunctionJITTimeInfo*>(m_data.ldFldInlinees[inlineCacheIndex]);
  274. }
  275. const FunctionJITTimeInfo *
  276. FunctionJITTimeInfo::GetInlinee(Js::ProfileId profileId) const
  277. {
  278. Assert(profileId < m_data.bodyData->profiledCallSiteCount);
  279. if (!m_data.inlinees)
  280. {
  281. return nullptr;
  282. }
  283. Assert(profileId < m_data.inlineeCount);
  284. auto inlinee = reinterpret_cast<const FunctionJITTimeInfo *>(m_data.inlinees[profileId]);
  285. if (inlinee == nullptr && m_data.inlineesRecursionFlags[profileId])
  286. {
  287. inlinee = this;
  288. }
  289. return inlinee;
  290. }
  291. const FunctionJITTimeInfo *
  292. FunctionJITTimeInfo::GetNext() const
  293. {
  294. return reinterpret_cast<const FunctionJITTimeInfo *>(m_data.next);
  295. }
  296. JITTimeFunctionBody *
  297. FunctionJITTimeInfo::GetBody() const
  298. {
  299. return reinterpret_cast<JITTimeFunctionBody *>(m_data.bodyData);
  300. }
  301. bool
  302. FunctionJITTimeInfo::HasBody() const
  303. {
  304. return m_data.bodyData != nullptr;
  305. }
  306. bool
  307. FunctionJITTimeInfo::IsPolymorphicCallSite(Js::ProfileId profiledCallSiteId) const
  308. {
  309. Assert(profiledCallSiteId < m_data.bodyData->profiledCallSiteCount);
  310. if (!m_data.inlinees)
  311. {
  312. return false;
  313. }
  314. Assert(profiledCallSiteId < m_data.inlineeCount);
  315. return ((FunctionJITTimeDataIDL*)this->GetInlinee(profiledCallSiteId))->next != nullptr;
  316. }
  317. bool
  318. FunctionJITTimeInfo::ForceJITLoopBody() const
  319. {
  320. return
  321. !PHASE_OFF(Js::JITLoopBodyPhase, this) &&
  322. !PHASE_OFF(Js::FullJitPhase, this) &&
  323. !GetBody()->IsGenerator() &&
  324. !GetBody()->HasTry() &&
  325. (
  326. PHASE_FORCE(Js::JITLoopBodyPhase, this)
  327. #ifdef ENABLE_PREJIT
  328. || Js::Configuration::Global.flags.Prejit
  329. #endif
  330. );
  331. }
  332. char16*
  333. FunctionJITTimeInfo::GetDisplayName() const
  334. {
  335. return GetBody()->GetDisplayName();
  336. }
  337. char16*
  338. FunctionJITTimeInfo::GetDebugNumberSet(wchar(&bufferToWriteTo)[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]) const
  339. {
  340. // (#%u.%u), #%u --> (source file Id . function Id) , function Number
  341. int len = swprintf_s(bufferToWriteTo, MAX_FUNCTION_BODY_DEBUG_STRING_SIZE, _u(" (#%d.%u), #%u"),
  342. (int)GetSourceContextId(), GetLocalFunctionId(), GetBody()->GetFunctionNumber());
  343. Assert(len > 8);
  344. return bufferToWriteTo;
  345. }