TTRuntimeInfoTracker.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "RuntimeDebugPch.h"
  7. #if ENABLE_TTD
  8. namespace TTD
  9. {
  10. void ThreadContextTTD::AddNewScriptContext_Helper(Js::ScriptContext* ctx, HostScriptContextCallbackFunctor& callbackFunctor, bool noNative, bool debugMode)
  11. {
  12. ////
  13. //First just setup the standard things needed for a script context
  14. ctx->TTDHostCallbackFunctor = callbackFunctor;
  15. if(noNative)
  16. {
  17. ctx->ForceNoNative();
  18. }
  19. if(debugMode)
  20. {
  21. #ifdef _WIN32
  22. ctx->InitializeDebugging();
  23. #else
  24. //
  25. //TODO: x-plat does not like some parts of initiallize debugging so just set the flag we need
  26. //
  27. ctx->GetDebugContext()->SetDebuggerMode(Js::DebuggerMode::Debugging);
  28. #endif
  29. }
  30. ctx->InitializeCoreImage_TTD();
  31. TTDAssert(!this->m_contextList.Contains(ctx), "We should only be adding at creation time!!!");
  32. this->m_contextList.Add(ctx);
  33. }
  34. void ThreadContextTTD::CleanRecordWeakRootMap()
  35. {
  36. this->m_ttdRecordRootWeakMap->Map([&](Js::RecyclableObject* key, bool, const RecyclerWeakReference<Js::RecyclableObject>*)
  37. {
  38. ; //nop just map to force the clean
  39. });
  40. }
  41. ThreadContextTTD::ThreadContextTTD(ThreadContext* threadContext, void* runtimeHandle, uint32 snapInterval, uint32 snapHistoryLength)
  42. : m_threadCtx(threadContext), m_runtimeHandle(runtimeHandle), m_contextCreatedOrDestoyedInReplay(false),
  43. SnapInterval(snapInterval), SnapHistoryLength(snapHistoryLength),
  44. m_activeContext(nullptr), m_contextList(&HeapAllocator::Instance), m_ttdContextToExternalRefMap(&HeapAllocator::Instance),
  45. m_ttdRootTagToObjectMap(&HeapAllocator::Instance), m_ttdMayBeLongLivedRoot(&HeapAllocator::Instance),
  46. m_ttdRecordRootWeakMap(),m_ttdReplayRootPinSet(),
  47. TTDataIOInfo({ 0 }), TTDExternalObjectFunctions({ 0 })
  48. {
  49. Recycler* tctxRecycler = this->m_threadCtx->GetRecycler();
  50. this->m_ttdRecordRootWeakMap.Root(RecyclerNew(tctxRecycler, RecordRootMap, tctxRecycler), tctxRecycler);
  51. this->m_ttdReplayRootPinSet.Root(RecyclerNew(tctxRecycler, ObjectPinSet, tctxRecycler), tctxRecycler);
  52. }
  53. ThreadContextTTD::~ThreadContextTTD()
  54. {
  55. for(auto iter = this->m_ttdContextToExternalRefMap.GetIterator(); iter.IsValid(); iter.MoveNext())
  56. {
  57. this->m_threadCtx->GetRecycler()->RootRelease(iter.CurrentValue());
  58. }
  59. this->m_ttdContextToExternalRefMap.Clear();
  60. this->m_activeContext = nullptr;
  61. this->m_contextList.Clear();
  62. this->m_ttdRootTagToObjectMap.Clear();
  63. this->m_ttdMayBeLongLivedRoot.Clear();
  64. if(this->m_ttdRecordRootWeakMap != nullptr)
  65. {
  66. this->m_ttdRecordRootWeakMap.Unroot(this->m_threadCtx->GetRecycler());
  67. }
  68. if(this->m_ttdReplayRootPinSet != nullptr)
  69. {
  70. this->m_ttdReplayRootPinSet.Unroot(this->m_threadCtx->GetRecycler());
  71. }
  72. }
  73. ThreadContext* ThreadContextTTD::GetThreadContext()
  74. {
  75. return this->m_threadCtx;
  76. }
  77. void* ThreadContextTTD::GetRuntimeHandle()
  78. {
  79. return this->m_runtimeHandle;
  80. }
  81. FinalizableObject* ThreadContextTTD::GetRuntimeContextForScriptContext(Js::ScriptContext* ctx)
  82. {
  83. return this->m_ttdContextToExternalRefMap.Lookup(ctx, nullptr);
  84. }
  85. bool ThreadContextTTD::ContextCreatedOrDestoyedInReplay() const
  86. {
  87. return this->m_contextCreatedOrDestoyedInReplay;
  88. }
  89. void ThreadContextTTD::ResetContextCreatedOrDestoyedInReplay()
  90. {
  91. this->m_contextCreatedOrDestoyedInReplay = false;
  92. }
  93. const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ThreadContextTTD::GetTTDContexts() const
  94. {
  95. return this->m_contextList;
  96. }
  97. void ThreadContextTTD::AddNewScriptContextRecord(FinalizableObject* externalCtx, Js::ScriptContext* ctx, HostScriptContextCallbackFunctor& callbackFunctor, bool noNative, bool debugMode)
  98. {
  99. this->AddNewScriptContext_Helper(ctx, callbackFunctor, noNative, debugMode);
  100. this->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetGlobalObject()), ctx->GetGlobalObject());
  101. ctx->ScriptContextLogTag = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetGlobalObject());
  102. this->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetLibrary()->GetUndefined()), ctx->GetLibrary()->GetUndefined());
  103. this->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetLibrary()->GetNull()), ctx->GetLibrary()->GetNull());
  104. this->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetLibrary()->GetTrue()), ctx->GetLibrary()->GetTrue());
  105. this->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(ctx->GetLibrary()->GetFalse()), ctx->GetLibrary()->GetFalse());
  106. }
  107. void ThreadContextTTD::AddNewScriptContextReplay(FinalizableObject* externalCtx, Js::ScriptContext* ctx, HostScriptContextCallbackFunctor& callbackFunctor, bool noNative, bool debugMode)
  108. {
  109. this->AddNewScriptContext_Helper(ctx, callbackFunctor, noNative, debugMode);
  110. this->m_contextCreatedOrDestoyedInReplay = true;
  111. this->m_threadCtx->GetRecycler()->RootAddRef(externalCtx);
  112. this->m_ttdContextToExternalRefMap.Add(ctx, externalCtx);
  113. }
  114. void ThreadContextTTD::SetActiveScriptContext(Js::ScriptContext* ctx)
  115. {
  116. TTDAssert(ctx == nullptr || this->m_contextList.Contains(ctx), "Missing value!!!");
  117. this->m_activeContext = ctx;
  118. }
  119. Js::ScriptContext* ThreadContextTTD::GetActiveScriptContext()
  120. {
  121. return this->m_activeContext;
  122. }
  123. void ThreadContextTTD::NotifyCtxDestroyInRecord(Js::ScriptContext* ctx)
  124. {
  125. if(this->m_contextList.Contains(ctx))
  126. {
  127. this->m_contextList.Remove(ctx);
  128. }
  129. }
  130. void ThreadContextTTD::ClearContextsForSnapRestore(JsUtil::List<FinalizableObject*, HeapAllocator>& deadCtxs)
  131. {
  132. for(int32 i = 0; i < this->m_contextList.Count(); ++i)
  133. {
  134. Js::ScriptContext* ctx = this->m_contextList.Item(i);
  135. FinalizableObject* externalCtx = this->m_ttdContextToExternalRefMap.Item(ctx);
  136. deadCtxs.Add(externalCtx);
  137. }
  138. this->m_ttdContextToExternalRefMap.Clear();
  139. this->m_contextList.Clear();
  140. this->m_activeContext = nullptr;
  141. }
  142. void ThreadContextTTD::ClearLocalRootsAndRefreshMap_Replay()
  143. {
  144. JsUtil::BaseHashSet<Js::RecyclableObject*, HeapAllocator> image(&HeapAllocator::Instance);
  145. this->m_ttdRootTagToObjectMap.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_LOG_PTR_ID, Js::RecyclableObject*>& entry) -> bool
  146. {
  147. bool localonly = !this->m_ttdMayBeLongLivedRoot.LookupWithKey(entry.Key(), false);
  148. if(!localonly)
  149. {
  150. image.AddNew(entry.Value());
  151. }
  152. return localonly;
  153. });
  154. this->m_ttdReplayRootPinSet->MapAndRemoveIf([&](Js::RecyclableObject* value) -> bool
  155. {
  156. return !image.Contains(value);
  157. });
  158. }
  159. void ThreadContextTTD::LoadInvertedRootMap(JsUtil::BaseDictionary<Js::RecyclableObject*, TTD_LOG_PTR_ID, HeapAllocator>& objToLogIdMap) const
  160. {
  161. for(auto iter = this->m_ttdRootTagToObjectMap.GetIterator(); iter.IsValid(); iter.MoveNext())
  162. {
  163. objToLogIdMap.AddNew(iter.CurrentValue(), iter.CurrentKey());
  164. }
  165. }
  166. Js::RecyclableObject* ThreadContextTTD::LookupObjectForLogID(TTD_LOG_PTR_ID origId)
  167. {
  168. //Local root always has mappings for all the ids
  169. return this->m_ttdRootTagToObjectMap.Item(origId);
  170. }
  171. void ThreadContextTTD::ClearRootsForSnapRestore()
  172. {
  173. this->m_ttdRootTagToObjectMap.Clear();
  174. this->m_ttdMayBeLongLivedRoot.Clear();
  175. this->m_ttdReplayRootPinSet->Clear();
  176. }
  177. void ThreadContextTTD::ForceSetRootInfoInRestore(TTD_LOG_PTR_ID logid, Js::RecyclableObject* obj, bool maybeLongLived)
  178. {
  179. this->m_ttdRootTagToObjectMap.Item(logid, obj);
  180. if(maybeLongLived)
  181. {
  182. this->m_ttdMayBeLongLivedRoot.Item(logid, maybeLongLived);
  183. }
  184. this->m_ttdReplayRootPinSet->AddNew(obj);
  185. }
  186. void ThreadContextTTD::SyncRootsBeforeSnapshot_Record()
  187. {
  188. this->CleanRecordWeakRootMap();
  189. this->m_ttdRootTagToObjectMap.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_LOG_PTR_ID, Js::RecyclableObject*>& entry) -> bool
  190. {
  191. return !this->m_ttdRecordRootWeakMap->Lookup(entry.Value(), false);
  192. });
  193. this->m_ttdMayBeLongLivedRoot.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_LOG_PTR_ID, bool>& entry) -> bool
  194. {
  195. return !this->m_ttdRootTagToObjectMap.ContainsKey(entry.Key());
  196. });
  197. }
  198. void ThreadContextTTD::SyncCtxtsAndRootsWithSnapshot_Replay(uint32 liveContextCount, TTD_LOG_PTR_ID* liveContextIdArray, uint32 liveRootCount, TTD_LOG_PTR_ID* liveRootIdArray)
  199. {
  200. //First sync up the context list -- releasing any contexts that are not also there in our initial recording
  201. JsUtil::BaseHashSet<TTD_LOG_PTR_ID, HeapAllocator> lctxSet(&HeapAllocator::Instance);
  202. for(uint32 i = 0; i < liveContextCount; ++i)
  203. {
  204. lctxSet.AddNew(liveContextIdArray[i]);
  205. }
  206. int32 ctxpos = 0;
  207. while(ctxpos < this->m_contextList.Count())
  208. {
  209. Js::ScriptContext* ctx = this->m_contextList.Item(ctxpos);
  210. if(lctxSet.Contains(ctx->ScriptContextLogTag))
  211. {
  212. ctxpos++;
  213. }
  214. else
  215. {
  216. this->m_contextCreatedOrDestoyedInReplay = true;
  217. this->m_contextList.Remove(ctx);
  218. FinalizableObject* externalCtx = this->m_ttdContextToExternalRefMap.Item(ctx);
  219. this->m_ttdContextToExternalRefMap.Remove(ctx);
  220. this->m_threadCtx->GetRecycler()->RootRelease(externalCtx);
  221. //no inc of ctxpos since list go shorter!!!
  222. }
  223. }
  224. //Now sync up the root list wrt. long lived roots that we recorded
  225. JsUtil::BaseHashSet<TTD_LOG_PTR_ID, HeapAllocator> refInfoMap(&HeapAllocator::Instance);
  226. for(uint32 i = 0; i < liveRootCount; ++i)
  227. {
  228. refInfoMap.AddNew(liveRootIdArray[i]);
  229. }
  230. this->m_ttdMayBeLongLivedRoot.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_LOG_PTR_ID, bool>& entry) -> bool
  231. {
  232. return !refInfoMap.Contains(entry.Key());
  233. });
  234. this->ClearLocalRootsAndRefreshMap_Replay();
  235. }
  236. Js::ScriptContext* ThreadContextTTD::LookupContextForScriptId(TTD_LOG_PTR_ID ctxId) const
  237. {
  238. for(int i = 0; i < this->m_contextList.Count(); ++i)
  239. {
  240. if(this->m_contextList.Item(i)->ScriptContextLogTag == ctxId)
  241. {
  242. return this->m_contextList.Item(i);
  243. }
  244. }
  245. return nullptr;
  246. }
  247. ScriptContextTTD::ScriptContextTTD(Js::ScriptContext* ctx)
  248. : m_ctx(ctx),
  249. m_ttdPendingAsyncModList(&HeapAllocator::Instance),
  250. m_ttdTopLevelScriptLoad(&HeapAllocator::Instance), m_ttdTopLevelNewFunction(&HeapAllocator::Instance), m_ttdTopLevelEval(&HeapAllocator::Instance),
  251. m_ttdFunctionBodyParentMap(&HeapAllocator::Instance)
  252. {
  253. Recycler* ctxRecycler = this->m_ctx->GetRecycler();
  254. this->m_ttdPinnedRootFunctionSet.Root(RecyclerNew(ctxRecycler, TTD::FunctionBodyPinSet, ctxRecycler), ctxRecycler);
  255. this->TTDWeakReferencePinSet.Root(RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler), ctxRecycler);
  256. }
  257. ScriptContextTTD::~ScriptContextTTD()
  258. {
  259. this->m_ttdPendingAsyncModList.Clear();
  260. this->m_ttdTopLevelScriptLoad.Clear();
  261. this->m_ttdTopLevelNewFunction.Clear();
  262. this->m_ttdTopLevelEval.Clear();
  263. if(this->m_ttdPinnedRootFunctionSet != nullptr)
  264. {
  265. this->m_ttdPinnedRootFunctionSet.Unroot(this->m_ttdPinnedRootFunctionSet->GetAllocator());
  266. }
  267. this->m_ttdFunctionBodyParentMap.Clear();
  268. if(this->TTDWeakReferencePinSet != nullptr)
  269. {
  270. this->TTDWeakReferencePinSet.Unroot(this->TTDWeakReferencePinSet->GetAllocator());
  271. }
  272. }
  273. void ScriptContextTTD::AddToAsyncPendingList(Js::ArrayBuffer* trgt, uint32 index)
  274. {
  275. TTDPendingAsyncBufferModification pending = { trgt, index };
  276. this->m_ttdPendingAsyncModList.Add(pending);
  277. }
  278. void ScriptContextTTD::GetFromAsyncPendingList(TTDPendingAsyncBufferModification* pendingInfo, byte* finalModPos)
  279. {
  280. pendingInfo->ArrayBufferVar = nullptr;
  281. pendingInfo->Index = 0;
  282. const byte* currentBegin = nullptr;
  283. int32 pos = -1;
  284. for(int32 i = 0; i < this->m_ttdPendingAsyncModList.Count(); ++i)
  285. {
  286. const TTDPendingAsyncBufferModification& pi = this->m_ttdPendingAsyncModList.Item(i);
  287. const Js::ArrayBuffer* pbuff = Js::VarTo<Js::ArrayBuffer>(pi.ArrayBufferVar);
  288. const byte* pbuffBegin = pbuff->GetBuffer() + pi.Index;
  289. const byte* pbuffMax = pbuff->GetBuffer() + pbuff->GetByteLength();
  290. //if the final mod is less than the start of this buffer + index or off then end then this definitely isn't it so skip
  291. if(pbuffBegin > finalModPos || pbuffMax < finalModPos)
  292. {
  293. continue;
  294. }
  295. //it is in the right range so now we assume non-overlapping so we see if this pbuffBegin is closer than the current best
  296. TTDAssert(finalModPos != currentBegin, "We have something strange!!!");
  297. if(currentBegin == nullptr || finalModPos < currentBegin)
  298. {
  299. currentBegin = pbuffBegin;
  300. pos = (int32)i;
  301. }
  302. }
  303. TTDAssert(pos != -1, "Missing matching register!!!");
  304. *pendingInfo = this->m_ttdPendingAsyncModList.Item(pos);
  305. this->m_ttdPendingAsyncModList.RemoveAt(pos);
  306. }
  307. const JsUtil::List<TTDPendingAsyncBufferModification, HeapAllocator>& ScriptContextTTD::GetPendingAsyncModListForSnapshot() const
  308. {
  309. return this->m_ttdPendingAsyncModList;
  310. }
  311. void ScriptContextTTD::ClearPendingAsyncModListForSnapRestore()
  312. {
  313. this->m_ttdPendingAsyncModList.Clear();
  314. }
  315. void ScriptContextTTD::GetLoadedSources(const JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>* onlyLiveTopLevelBodies, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelScriptLoad, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelNewFunction, JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator>& topLevelEval)
  316. {
  317. TTDAssert(topLevelScriptLoad.Count() == 0 && topLevelNewFunction.Count() == 0 && topLevelEval.Count() == 0, "Should be empty when you call this.");
  318. for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext())
  319. {
  320. Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  321. if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
  322. {
  323. topLevelScriptLoad.Add(iter.CurrentValue());
  324. }
  325. }
  326. for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext())
  327. {
  328. Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  329. if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
  330. {
  331. topLevelNewFunction.Add(iter.CurrentValue());
  332. }
  333. }
  334. for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext())
  335. {
  336. Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  337. if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body))
  338. {
  339. topLevelEval.Add(iter.CurrentValue());
  340. }
  341. }
  342. }
  343. bool ScriptContextTTD::IsBodyAlreadyLoadedAtTopLevel(Js::FunctionBody* body) const
  344. {
  345. return this->m_ttdPinnedRootFunctionSet->Contains(body);
  346. }
  347. void ScriptContextTTD::ProcessFunctionBodyOnLoad(Js::FunctionBody* body, Js::FunctionBody* parent)
  348. {
  349. //if this is a root (parent is null) then put this in the rootbody pin set so it isn't reclaimed on us
  350. if(parent == nullptr)
  351. {
  352. TTDAssert(!this->m_ttdPinnedRootFunctionSet->Contains(body), "We already added this function!!!");
  353. this->m_ttdPinnedRootFunctionSet->AddNew(body);
  354. }
  355. this->m_ttdFunctionBodyParentMap.AddNew(body, parent);
  356. for(uint32 i = 0; i < body->GetNestedCount(); ++i)
  357. {
  358. Js::ParseableFunctionInfo* pfiMid = body->GetNestedFunctionForExecution(i);
  359. Js::FunctionBody* currfb = TTD::JsSupport::ForceAndGetFunctionBody(pfiMid);
  360. this->ProcessFunctionBodyOnLoad(currfb, body);
  361. }
  362. }
  363. void ScriptContextTTD::ProcessFunctionBodyOnUnLoad(Js::FunctionBody* body, Js::FunctionBody* parent)
  364. {
  365. //if this is a root (parent is null) then put this in the rootbody pin set so it isn't reclaimed on us
  366. if(parent == nullptr)
  367. {
  368. TTDAssert(this->m_ttdPinnedRootFunctionSet->Contains(body), "We already added this function!!!");
  369. this->m_ttdPinnedRootFunctionSet->Remove(body);
  370. }
  371. this->m_ttdFunctionBodyParentMap.Remove(body);
  372. for(uint32 i = 0; i < body->GetNestedCount(); ++i)
  373. {
  374. Js::ParseableFunctionInfo* pfiMid = body->GetNestedFunctionForExecution(i);
  375. Js::FunctionBody* currfb = TTD::JsSupport::ForceAndGetFunctionBody(pfiMid);
  376. this->ProcessFunctionBodyOnUnLoad(currfb, body);
  377. }
  378. }
  379. void ScriptContextTTD::RegisterLoadedScript(Js::FunctionBody* body, uint32 bodyCtrId)
  380. {
  381. TTD::TopLevelFunctionInContextRelation relation;
  382. relation.TopLevelBodyCtr = bodyCtrId;
  383. relation.ContextSpecificBodyPtrId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(body);
  384. this->m_ttdTopLevelScriptLoad.Add(relation.ContextSpecificBodyPtrId, relation);
  385. }
  386. void ScriptContextTTD::RegisterNewScript(Js::FunctionBody* body, uint32 bodyCtrId)
  387. {
  388. TTD::TopLevelFunctionInContextRelation relation;
  389. relation.TopLevelBodyCtr = bodyCtrId;
  390. relation.ContextSpecificBodyPtrId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(body);
  391. this->m_ttdTopLevelNewFunction.Add(relation.ContextSpecificBodyPtrId, relation);
  392. }
  393. void ScriptContextTTD::RegisterEvalScript(Js::FunctionBody* body, uint32 bodyCtrId)
  394. {
  395. TTD::TopLevelFunctionInContextRelation relation;
  396. relation.TopLevelBodyCtr = bodyCtrId;
  397. relation.ContextSpecificBodyPtrId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(body);
  398. this->m_ttdTopLevelEval.Add(relation.ContextSpecificBodyPtrId, relation);
  399. }
  400. void ScriptContextTTD::CleanUnreachableTopLevelBodies(const JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>& liveTopLevelBodies)
  401. {
  402. //don't clear top-level loaded bodies
  403. this->m_ttdTopLevelNewFunction.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_PTR_ID, TTD::TopLevelFunctionInContextRelation>& entry) -> bool {
  404. Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(entry.Value().ContextSpecificBodyPtrId);
  405. if(liveTopLevelBodies.Contains(body))
  406. {
  407. return false;
  408. }
  409. else
  410. {
  411. this->ProcessFunctionBodyOnUnLoad(body, nullptr);
  412. return true;
  413. }
  414. });
  415. this->m_ttdTopLevelEval.MapAndRemoveIf([&](JsUtil::SimpleDictionaryEntry<TTD_PTR_ID, TTD::TopLevelFunctionInContextRelation>& entry) -> bool {
  416. Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(entry.Value().ContextSpecificBodyPtrId);
  417. if(liveTopLevelBodies.Contains(body))
  418. {
  419. return false;
  420. }
  421. else
  422. {
  423. this->ProcessFunctionBodyOnUnLoad(body, nullptr);
  424. return true;
  425. }
  426. });
  427. }
  428. Js::FunctionBody* ScriptContextTTD::ResolveParentBody(Js::FunctionBody* body) const
  429. {
  430. //Want to return null if this has no parent (or this is an internal function and we don't care about parents)
  431. return this->m_ttdFunctionBodyParentMap.LookupWithKey(body, nullptr);
  432. }
  433. uint32 ScriptContextTTD::FindTopLevelCtrForBody(Js::FunctionBody* body) const
  434. {
  435. Js::FunctionBody* rootBody = body;
  436. while(this->ResolveParentBody(rootBody) != nullptr)
  437. {
  438. rootBody = this->ResolveParentBody(rootBody);
  439. }
  440. TTD_PTR_ID trgtid = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(rootBody);
  441. for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext())
  442. {
  443. if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid)
  444. {
  445. return iter.CurrentValue().TopLevelBodyCtr;
  446. }
  447. }
  448. for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext())
  449. {
  450. if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid)
  451. {
  452. return iter.CurrentValue().TopLevelBodyCtr;
  453. }
  454. }
  455. for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext())
  456. {
  457. if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid)
  458. {
  459. return iter.CurrentValue().TopLevelBodyCtr;
  460. }
  461. }
  462. TTDAssert(false, "We are missing a top-level function reference.");
  463. return 0;
  464. }
  465. Js::FunctionBody* ScriptContextTTD::FindRootBodyByTopLevelCtr(uint32 bodyCtrId) const
  466. {
  467. for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext())
  468. {
  469. if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId)
  470. {
  471. return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  472. }
  473. }
  474. for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext())
  475. {
  476. if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId)
  477. {
  478. return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  479. }
  480. }
  481. for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext())
  482. {
  483. if(iter.CurrentValue().TopLevelBodyCtr == bodyCtrId)
  484. {
  485. return TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId);
  486. }
  487. }
  488. return nullptr;
  489. }
  490. void ScriptContextTTD::ClearLoadedSourcesForSnapshotRestore()
  491. {
  492. this->m_ttdTopLevelScriptLoad.Clear();
  493. this->m_ttdTopLevelNewFunction.Clear();
  494. this->m_ttdTopLevelEval.Clear();
  495. this->m_ttdPinnedRootFunctionSet->Clear();
  496. this->m_ttdFunctionBodyParentMap.Clear();
  497. }
  498. //////////////////
  499. void RuntimeContextInfo::BuildPathString(UtilSupport::TTAutoString rootpath, const char16* name, const char16* optaccessortag, UtilSupport::TTAutoString& into)
  500. {
  501. into.Append(rootpath);
  502. into.Append(_u("."));
  503. into.Append(name);
  504. if(optaccessortag != nullptr)
  505. {
  506. into.Append(optaccessortag);
  507. }
  508. }
  509. void RuntimeContextInfo::LoadAndOrderPropertyNames(Js::RecyclableObject* obj, JsUtil::List<const Js::PropertyRecord*, HeapAllocator>& propertyList)
  510. {
  511. TTDAssert(propertyList.Count() == 0, "This should be empty.");
  512. Js::ScriptContext* ctx = obj->GetScriptContext();
  513. uint32 propcount = (uint32)obj->GetPropertyCount();
  514. //get all of the properties
  515. for(uint32 i = 0; i < propcount; ++i)
  516. {
  517. Js::PropertyIndex propertyIndex = (Js::PropertyIndex)i;
  518. Js::PropertyId propertyId = obj->GetPropertyId(propertyIndex);
  519. if((propertyId != Js::Constants::NoProperty) & (!Js::IsInternalPropertyId(propertyId)))
  520. {
  521. TTDAssert(obj->HasOwnProperty(propertyId), "We are assuming this is own property count.");
  522. propertyList.Add(ctx->GetPropertyName(propertyId));
  523. }
  524. }
  525. //now sort the list so the traversal order is stable
  526. //Rock a custom shell sort!!!!
  527. const int32 gaps[6] = { 132, 57, 23, 10, 4, 1 };
  528. int32 llen = propertyList.Count();
  529. for(uint32 gapi = 0; gapi < 6; ++gapi)
  530. {
  531. int32 gap = gaps[gapi];
  532. for(int32 i = gap; i < llen; i++)
  533. {
  534. const Js::PropertyRecord* temp = propertyList.Item(i);
  535. int32 j = 0;
  536. for(j = i; j >= gap && PropertyNameCmp(propertyList.Item(j - gap), temp); j -= gap)
  537. {
  538. const Js::PropertyRecord* shiftElem = propertyList.Item(j - gap);
  539. propertyList.SetItem(j, shiftElem);
  540. }
  541. propertyList.SetItem(j, temp);
  542. }
  543. }
  544. }
  545. bool RuntimeContextInfo::PropertyNameCmp(const Js::PropertyRecord* p1, const Js::PropertyRecord* p2)
  546. {
  547. if(p1->GetLength() != p2->GetLength())
  548. {
  549. return p1->GetLength() > p2->GetLength();
  550. }
  551. else
  552. {
  553. return wcscmp(p1->GetBuffer(), p2->GetBuffer()) > 0;
  554. }
  555. }
  556. RuntimeContextInfo::RuntimeContextInfo()
  557. : m_worklist(&HeapAllocator::Instance), m_nullString(),
  558. m_coreObjToPathMap(&HeapAllocator::Instance, TTD_CORE_OBJECT_COUNT), m_coreBodyToPathMap(&HeapAllocator::Instance, TTD_CORE_FUNCTION_BODY_COUNT), m_coreDbgScopeToPathMap(&HeapAllocator::Instance, TTD_CORE_FUNCTION_BODY_COUNT),
  559. m_sortedObjectList(&HeapAllocator::Instance, TTD_CORE_OBJECT_COUNT), m_sortedFunctionBodyList(&HeapAllocator::Instance, TTD_CORE_FUNCTION_BODY_COUNT), m_sortedDbgScopeList(&HeapAllocator::Instance, TTD_CORE_FUNCTION_BODY_COUNT)
  560. {
  561. ;
  562. }
  563. RuntimeContextInfo::~RuntimeContextInfo()
  564. {
  565. for(auto iter = this->m_coreObjToPathMap.GetIterator(); iter.IsValid(); iter.MoveNext())
  566. {
  567. TT_HEAP_DELETE(UtilSupport::TTAutoString, iter.CurrentValue());
  568. }
  569. for(auto iter = this->m_coreBodyToPathMap.GetIterator(); iter.IsValid(); iter.MoveNext())
  570. {
  571. TT_HEAP_DELETE(UtilSupport::TTAutoString, iter.CurrentValue());
  572. }
  573. for(auto iter = this->m_coreDbgScopeToPathMap.GetIterator(); iter.IsValid(); iter.MoveNext())
  574. {
  575. TT_HEAP_DELETE(UtilSupport::TTAutoString, iter.CurrentValue());
  576. }
  577. }
  578. //Mark all the well-known objects/values/types from this script context
  579. void RuntimeContextInfo::MarkWellKnownObjects_TTD(MarkTable& marks) const
  580. {
  581. for(int32 i = 0; i < this->m_sortedObjectList.Count(); ++i)
  582. {
  583. Js::RecyclableObject* obj = this->m_sortedObjectList.Item(i);
  584. marks.MarkAddrWithSpecialInfo<MarkTableTag::JsWellKnownObj>(obj);
  585. }
  586. for(int32 i = 0; i < this->m_sortedFunctionBodyList.Count(); ++i)
  587. {
  588. Js::FunctionBody* body = this->m_sortedFunctionBodyList.Item(i);
  589. marks.MarkAddrWithSpecialInfo<MarkTableTag::JsWellKnownObj>(body);
  590. }
  591. }
  592. TTD_WELLKNOWN_TOKEN RuntimeContextInfo::ResolvePathForKnownObject(Js::RecyclableObject* obj) const
  593. {
  594. const UtilSupport::TTAutoString* res = this->m_coreObjToPathMap.Item(obj);
  595. return res->GetStrValue();
  596. }
  597. TTD_WELLKNOWN_TOKEN RuntimeContextInfo::ResolvePathForKnownFunctionBody(Js::FunctionBody* fbody) const
  598. {
  599. const UtilSupport::TTAutoString* res = this->m_coreBodyToPathMap.Item(fbody);
  600. return res->GetStrValue();
  601. }
  602. TTD_WELLKNOWN_TOKEN RuntimeContextInfo::ResolvePathForKnownDbgScopeIfExists(Js::DebuggerScope* dbgScope) const
  603. {
  604. const UtilSupport::TTAutoString* res = this->m_coreDbgScopeToPathMap.LookupWithKey(dbgScope, nullptr);
  605. if(res == nullptr)
  606. {
  607. return nullptr;
  608. }
  609. return res->GetStrValue();
  610. }
  611. Js::RecyclableObject* RuntimeContextInfo::LookupKnownObjectFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const
  612. {
  613. int32 pos = LookupPositionInDictNameList<Js::RecyclableObject*, true>(pathIdString, this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString);
  614. TTDAssert(pos != -1, "This isn't a well known object!");
  615. return this->m_sortedObjectList.Item(pos);
  616. }
  617. Js::FunctionBody* RuntimeContextInfo::LookupKnownFunctionBodyFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const
  618. {
  619. int32 pos = LookupPositionInDictNameList<Js::FunctionBody*, true>(pathIdString, this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString);
  620. TTDAssert(pos != -1, "Missing function.");
  621. return (pos != -1) ? this->m_sortedFunctionBodyList.Item(pos) : nullptr;
  622. }
  623. Js::DebuggerScope* RuntimeContextInfo::LookupKnownDebuggerScopeFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const
  624. {
  625. int32 pos = LookupPositionInDictNameList<Js::DebuggerScope*, true>(pathIdString, this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString);
  626. TTDAssert(pos != -1, "Missing debug scope.");
  627. return (pos != -1) ? this->m_sortedDbgScopeList.Item(pos) : nullptr;
  628. }
  629. void RuntimeContextInfo::GatherKnownObjectToPathMap(Js::ScriptContext* ctx)
  630. {
  631. JsUtil::List<const Js::PropertyRecord*, HeapAllocator> propertyRecordList(&HeapAllocator::Instance);
  632. this->EnqueueRootPathObject(_u("global"), ctx->GetGlobalObject());
  633. this->EnqueueRootPathObject(_u("null"), ctx->GetLibrary()->GetNull());
  634. this->EnqueueRootPathObject(_u("undeclBlockVar"), Js::VarTo<Js::RecyclableObject>(ctx->GetLibrary()->GetUndeclBlockVar()));
  635. this->EnqueueRootPathObject(_u("_defaultAccessor"), ctx->GetLibrary()->GetDefaultAccessorFunction());
  636. if(ctx->GetConfig()->IsErrorStackTraceEnabled())
  637. {
  638. this->EnqueueRootPathObject(_u("_stackTraceAccessor"), ctx->GetLibrary()->GetStackTraceAccessorFunction());
  639. }
  640. this->EnqueueRootPathObject(_u("_throwTypeErrorRestrictedPropertyAccessor"), ctx->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction());
  641. this->EnqueueRootPathObject(_u("_identityFunction"), ctx->GetLibrary()->GetIdentityFunction());
  642. this->EnqueueRootPathObject(_u("_throwerFunction"), ctx->GetLibrary()->GetThrowerFunction());
  643. // ArrayIteratorPrototype is not created when we have JsBuiltins, it it created on-demand only
  644. #ifdef ENABLE_JS_BUILTINS
  645. if (ctx->IsJsBuiltInEnabled())
  646. {
  647. ctx->GetLibrary()->EnsureArrayBuiltInsAreReady();
  648. }
  649. #endif
  650. this->EnqueueRootPathObject(_u("_arrayIteratorPrototype"), ctx->GetLibrary()->GetArrayIteratorPrototype());
  651. this->EnqueueRootPathObject(_u("_mapIteratorPrototype"), ctx->GetLibrary()->GetMapIteratorPrototype());
  652. this->EnqueueRootPathObject(_u("_setIteratorPrototype"), ctx->GetLibrary()->GetSetIteratorPrototype());
  653. this->EnqueueRootPathObject(_u("_stringIteratorPrototype"), ctx->GetLibrary()->GetStringIteratorPrototype());
  654. this->EnqueueRootPathObject(_u("_generatorNextFunction"), ctx->GetLibrary()->EnsureGeneratorNextFunction());
  655. this->EnqueueRootPathObject(_u("_generatorReturnFunction"), ctx->GetLibrary()->EnsureGeneratorReturnFunction());
  656. this->EnqueueRootPathObject(_u("_generatorThrowFunction"), ctx->GetLibrary()->EnsureGeneratorThrowFunction());
  657. this->EnqueueRootPathObject(_u("_generatorFunctionConstructor"), ctx->GetLibrary()->GetGeneratorFunctionConstructor());
  658. this->EnqueueRootPathObject(_u("_asyncFunctionConstructor"), ctx->GetLibrary()->GetAsyncFunctionConstructor());
  659. uint32 counter = 0;
  660. while(!this->m_worklist.Empty())
  661. {
  662. Js::RecyclableObject* curr = this->m_worklist.Dequeue();
  663. counter++;
  664. ////
  665. //Handle the standard properties for all object types
  666. //load propArray with all property names
  667. propertyRecordList.Clear();
  668. LoadAndOrderPropertyNames(curr, propertyRecordList);
  669. //access each property and process the target objects as needed
  670. for(int32 i = 0; i < propertyRecordList.Count(); ++i)
  671. {
  672. const Js::PropertyRecord* precord = propertyRecordList.Item(i);
  673. Js::Var getter = nullptr;
  674. Js::Var setter = nullptr;
  675. if(curr->GetAccessors(precord->GetPropertyId(), &getter, &setter, ctx))
  676. {
  677. if(getter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(getter))
  678. {
  679. TTDAssert(Js::VarIs<Js::JavascriptFunction>(getter), "The getter is not a function?");
  680. this->EnqueueNewPathVarAsNeeded(curr, getter, precord, _u(">"));
  681. }
  682. if(setter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(setter))
  683. {
  684. TTDAssert(Js::VarIs<Js::JavascriptFunction>(setter), "The setter is not a function?");
  685. this->EnqueueNewPathVarAsNeeded(curr, Js::VarTo<Js::RecyclableObject>(setter), precord, _u("<"));
  686. }
  687. }
  688. else
  689. {
  690. Js::Var pitem = nullptr;
  691. BOOL isproperty = Js::JavascriptOperators::GetOwnProperty(curr, precord->GetPropertyId(), &pitem, ctx, nullptr);
  692. TTDAssert(isproperty, "Not sure what went wrong.");
  693. this->EnqueueNewPathVarAsNeeded(curr, pitem, precord, nullptr);
  694. }
  695. }
  696. //shouldn't have any dynamic array valued properties
  697. if(Js::DynamicType::Is(curr->GetTypeId()))
  698. {
  699. Js::ArrayObject* parray = Js::VarTo<Js::DynamicObject>(curr)->GetObjectArray();
  700. if(parray != nullptr)
  701. {
  702. this->EnqueueNewPathVarAsNeeded(curr, parray, _u("_object_array_"));
  703. }
  704. }
  705. Js::RecyclableObject* proto = curr->GetPrototype();
  706. bool skipProto = (proto == nullptr) || Js::JavascriptOperators::IsUndefinedOrNullType(proto->GetTypeId());
  707. if(!skipProto)
  708. {
  709. this->EnqueueNewPathVarAsNeeded(curr, proto, _u("_proto_"));
  710. }
  711. curr->ProcessCorePaths();
  712. }
  713. SortDictIntoListOnNames<Js::RecyclableObject*>(this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString);
  714. SortDictIntoListOnNames<Js::FunctionBody*>(this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString);
  715. SortDictIntoListOnNames<Js::DebuggerScope*>(this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString);
  716. }
  717. ////
  718. void RuntimeContextInfo::EnqueueRootPathObject(const char16* rootName, Js::RecyclableObject* obj)
  719. {
  720. this->m_worklist.Enqueue(obj);
  721. UtilSupport::TTAutoString* rootStr = TT_HEAP_NEW(UtilSupport::TTAutoString, rootName);
  722. TTDAssert(!this->m_coreObjToPathMap.ContainsKey(obj), "Already in map!!!");
  723. this->m_coreObjToPathMap.AddNew(obj, rootStr);
  724. }
  725. void RuntimeContextInfo::EnqueueNewPathVarAsNeeded(Js::RecyclableObject* parent, Js::Var val, const Js::PropertyRecord* prop, const char16* optacessortag)
  726. {
  727. this->EnqueueNewPathVarAsNeeded(parent, val, prop->GetBuffer(), optacessortag);
  728. }
  729. void RuntimeContextInfo::EnqueueNewPathVarAsNeeded(Js::RecyclableObject* parent, Js::Var val, const char16* propName, const char16* optacessortag)
  730. {
  731. if(JsSupport::IsVarTaggedInline(val))
  732. {
  733. return;
  734. }
  735. if(JsSupport::IsVarPrimitiveKind(val) && !Js::VarIs<Js::GlobalObject>(parent))
  736. {
  737. return; //we keep primitives from global object only -- may need others but this is a simple way to start to get undefined, null, infy, etc.
  738. }
  739. Js::RecyclableObject* obj = Js::VarTo<Js::RecyclableObject>(val);
  740. if(!this->m_coreObjToPathMap.ContainsKey(obj))
  741. {
  742. const UtilSupport::TTAutoString* ppath = this->m_coreObjToPathMap.Item(parent);
  743. this->m_worklist.Enqueue(obj);
  744. UtilSupport::TTAutoString* tpath = TT_HEAP_NEW(UtilSupport::TTAutoString, *ppath);
  745. tpath->Append(_u("."));
  746. tpath->Append(propName);
  747. if(optacessortag != nullptr)
  748. {
  749. tpath->Append(optacessortag);
  750. }
  751. TTDAssert(!this->m_coreObjToPathMap.ContainsKey(obj), "Already in map!!!");
  752. this->m_coreObjToPathMap.AddNew(obj, tpath);
  753. }
  754. }
  755. void RuntimeContextInfo::EnqueueNewFunctionBodyObject(Js::RecyclableObject* parent, Js::FunctionBody* fbody, const char16* name)
  756. {
  757. if(!this->m_coreBodyToPathMap.ContainsKey(fbody))
  758. {
  759. fbody->EnsureDeserialized();
  760. const UtilSupport::TTAutoString* ppath = this->m_coreObjToPathMap.Item(parent);
  761. UtilSupport::TTAutoString* fpath = TT_HEAP_NEW(UtilSupport::TTAutoString, *ppath);
  762. fpath->Append(_u("."));
  763. fpath->Append(name);
  764. this->m_coreBodyToPathMap.AddNew(fbody, fpath);
  765. }
  766. }
  767. void RuntimeContextInfo::AddWellKnownDebuggerScopePath(Js::RecyclableObject* parent, Js::DebuggerScope* dbgScope, uint32 index)
  768. {
  769. if(!this->m_coreDbgScopeToPathMap.ContainsKey(dbgScope))
  770. {
  771. const UtilSupport::TTAutoString* ppath = this->m_coreObjToPathMap.Item(parent);
  772. UtilSupport::TTAutoString* scpath = TT_HEAP_NEW(UtilSupport::TTAutoString, *ppath);
  773. scpath->Append(_u(".!scope["));
  774. scpath->Append(index);
  775. scpath->Append(_u("]"));
  776. this->m_coreDbgScopeToPathMap.AddNew(dbgScope, scpath);
  777. }
  778. }
  779. void RuntimeContextInfo::BuildArrayIndexBuffer(uint32 arrayidx, UtilSupport::TTAutoString& res)
  780. {
  781. res.Append(_u("!arrayContents["));
  782. res.Append(arrayidx);
  783. res.Append(_u("]"));
  784. }
  785. void RuntimeContextInfo::BuildEnvironmentIndexBuffer(uint32 envidx, UtilSupport::TTAutoString& res)
  786. {
  787. res.Append(_u("!env["));
  788. res.Append(envidx);
  789. res.Append(_u("]"));
  790. }
  791. void RuntimeContextInfo::BuildEnvironmentIndexAndSlotBuffer(uint32 envidx, uint32 slotidx, UtilSupport::TTAutoString& res)
  792. {
  793. res.Append(_u("!env["));
  794. res.Append(envidx);
  795. res.Append(_u("].!slot["));
  796. res.Append(slotidx);
  797. res.Append(_u("]"));
  798. }
  799. }
  800. #endif