TTRuntmeInfoTracker.cpp 39 KB

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