FunctionJITTimeInfo.cpp 13 KB

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