//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once #if ENABLE_TTD namespace TTD { //A class that manages inflation maps during heap state restoration class InflateMap { private: TTDIdentifierDictionary m_handlerMap; TTDIdentifierDictionary m_typeMap; //The maps for script contexts and objects TTDIdentifierDictionary m_tagToGlobalObjectMap; //get the script context from here TTDIdentifierDictionary m_objectMap; //The maps for inflated function bodies TTDIdentifierDictionary m_functionBodyMap; TTDIdentifierDictionary m_environmentMap; TTDIdentifierDictionary m_slotArrayMap; //The maps for resolving debug scopes TTDIdentifierDictionary m_debuggerScopeHomeBodyMap; TTDIdentifierDictionary m_debuggerScopeChainIndexMap; //A dictionary for the Promise related bits (not typesafe and a bit ugly but I prefer it to creating multiple additional collections) JsUtil::BaseDictionary m_promiseDataMap; //A set we use to pin all the inflated objects live during/after the inflate process (to avoid accidental collection) RecyclerRootPtr m_inflatePinSet; RecyclerRootPtr m_environmentPinSet; RecyclerRootPtr m_slotArrayPinSet; //A set we use to keep some old objects alive during inflate in case we want to re-use them RecyclerRootPtr m_oldInflatePinSet; //Temp data structures for holding info during the inflate process TTDIdentifierDictionary m_oldObjectMap; TTDIdentifierDictionary m_oldFunctionBodyMap; JsUtil::BaseHashSet m_propertyReset; public: InflateMap(); ~InflateMap(); void PrepForInitialInflate(ThreadContext* threadContext, uint32 ctxCount, uint32 handlerCount, uint32 typeCount, uint32 objectCount, uint32 bodyCount, uint32 dbgScopeCount, uint32 envCount, uint32 slotCount); void PrepForReInflate(uint32 ctxCount, uint32 handlerCount, uint32 typeCount, uint32 objectCount, uint32 bodyCount, uint32 dbgScopeCount, uint32 envCount, uint32 slotCount); void CleanupAfterInflate(); bool IsObjectAlreadyInflated(TTD_PTR_ID objid) const; bool IsFunctionBodyAlreadyInflated(TTD_PTR_ID fbodyid) const; Js::RecyclableObject* FindReusableObjectIfExists(TTD_PTR_ID objid) const; Js::FunctionBody* FindReusableFunctionBodyIfExists(TTD_PTR_ID fbodyid) const; //A version of FindReusableObjectIfExists but we haven't moved the last inflate objects to oldObjects yet so we need to look in a differnt location Js::RecyclableObject* FindReusableObject_WellKnowReuseCheck(TTD_PTR_ID objid) const; //// Js::DynamicTypeHandler* LookupHandler(TTD_PTR_ID handlerId) const; Js::Type* LookupType(TTD_PTR_ID typeId) const; Js::ScriptContext* LookupScriptContext(TTD_LOG_PTR_ID sctag) const; Js::RecyclableObject* LookupObject(TTD_PTR_ID objid) const; Js::FunctionBody* LookupFunctionBody(TTD_PTR_ID functionId) const; Js::FrameDisplay* LookupEnvironment(TTD_PTR_ID envid) const; Field(Js::Var)* LookupSlotArray(TTD_PTR_ID slotid) const; void LookupInfoForDebugScope(TTD_PTR_ID dbgScopeId, Js::FunctionBody** homeBody, int32* chainIndex) const; //// void AddDynamicHandler(TTD_PTR_ID handlerId, Js::DynamicTypeHandler* value); void AddType(TTD_PTR_ID typeId, Js::Type* value); void AddScriptContext(TTD_LOG_PTR_ID sctag, Js::ScriptContext* value); void AddObject(TTD_PTR_ID objid, Js::RecyclableObject* value); void AddInflationFunctionBody(TTD_PTR_ID functionId, Js::FunctionBody* value); void AddEnvironment(TTD_PTR_ID envId, Js::FrameDisplay* value); void AddSlotArray(TTD_PTR_ID slotId, Field(Js::Var)* value); void UpdateFBScopes(const NSSnapValues::SnapFunctionBodyScopeChain& scopeChainInfo, Js::FunctionBody* fb); //// //Get the inflate stack and property reset set to use for depends on processing JsUtil::BaseHashSet& GetPropertyResetSet(); Js::Var InflateTTDVar(TTDVar var) const; //// template bool IsPromiseInfoDefined(TTD_PTR_ID ptrId) const { return this->m_promiseDataMap.ContainsKey(ptrId); } template void AddInflatedPromiseInfo(TTD_PTR_ID ptrId, T* data) { this->m_promiseDataMap.AddNew(ptrId, data); } template T* LookupInflatedPromiseInfo(TTD_PTR_ID ptrId) const { return (T*)this->m_promiseDataMap.Item(ptrId); } }; ////////////////// #if ENABLE_SNAPSHOT_COMPARE enum class TTDCompareTag { Done, //Values should not be matched by ptr -- should be immediately matched by value SlotArray, FunctionScopeInfo, TopLevelLoadFunction, TopLevelNewFunction, TopLevelEvalFunction, FunctionBody, SnapObject }; class TTDCompareMap; typedef void(*fPtr_AssertSnapEquivAddtlInfo)(const NSSnapObjects::SnapObject* v1, const NSSnapObjects::SnapObject* v2, TTDCompareMap& compareMap); class TTDComparePath { public: enum class StepKind { Empty, Root, PropertyData, PropertyGetter, PropertySetter, Array, Scope, SlotArray, FunctionBody, Special, SpecialArray }; struct PathEntry { int64 IndexOrPID; const char16* OptName; }; private: const StepKind m_stepKind; const TTDComparePath* m_prefix; const PathEntry m_step; public: TTDComparePath(); TTDComparePath(const TTDComparePath* prefix, StepKind stepKind, const PathEntry& nextStep); ~TTDComparePath(); void WritePathToConsole(ThreadContext* threadContext, bool printNewline, _Out_writes_z_(namebuffLength) char16* namebuff, charcount_t namebuffLength) const; }; //A class that we use to manage all the dictionaries we need when comparing 2 snapshots class TTDCompareMap { public: bool StrictCrossSite; JsUtil::Queue H1PtrIdWorklist; JsUtil::BaseDictionary H1PtrToH2PtrMap; TTDComparePath* CurrentPath; TTD_PTR_ID CurrentH1Ptr; TTD_PTR_ID CurrentH2Ptr; ThreadContext* Context; char16* PathBuffer; JsUtil::BaseDictionary H1PtrToPathMap; fPtr_AssertSnapEquivAddtlInfo* SnapObjCmpVTable; //// //H1 Maps JsUtil::BaseDictionary H1ValueMap; JsUtil::BaseDictionary H1SlotArrayMap; JsUtil::BaseDictionary H1FunctionScopeInfoMap; JsUtil::BaseDictionary H1FunctionTopLevelLoadMap; JsUtil::BaseDictionary H1FunctionTopLevelNewMap; JsUtil::BaseDictionary H1FunctionTopLevelEvalMap; JsUtil::BaseDictionary H1FunctionBodyMap; JsUtil::BaseDictionary H1ObjectMap; JsUtil::BaseHashSet H1PendingAsyncModBufferSet; //// //H2 Maps JsUtil::BaseDictionary H2ValueMap; JsUtil::BaseDictionary H2SlotArrayMap; JsUtil::BaseDictionary H2FunctionScopeInfoMap; JsUtil::BaseDictionary H2FunctionTopLevelLoadMap; JsUtil::BaseDictionary H2FunctionTopLevelNewMap; JsUtil::BaseDictionary H2FunctionTopLevelEvalMap; JsUtil::BaseDictionary H2FunctionBodyMap; JsUtil::BaseDictionary H2ObjectMap; JsUtil::BaseHashSet H2PendingAsyncModBufferSet; //// //Code TTDCompareMap(ThreadContext* threadContext); ~TTDCompareMap(); //Assert the condition must be true and report if not void DiagnosticAssert(bool condition); //Check that the given mapping either (1) does not exist or (2) is consistent -- if needed add the mapping and to worklist as well void CheckConsistentAndAddPtrIdMapping_Helper(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId, TTDComparePath::StepKind stepKind, const TTDComparePath::PathEntry& next); void CheckConsistentAndAddPtrIdMapping_Scope(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId, uint32 index); void CheckConsistentAndAddPtrIdMapping_FunctionBody(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId); void CheckConsistentAndAddPtrIdMapping_Special(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId, const char16* specialField); void CheckConsistentAndAddPtrIdMapping_Root(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId, TTD_LOG_PTR_ID tag); //Check if the given mapping is consistent but do not enqueue or try to lookup ptr id in any of the maps (used mainly for heap allocated promise info that may be shared) void CheckConsistentAndAddPtrIdMapping_NoEnqueue(TTD_PTR_ID h1PtrId, TTD_PTR_ID h2PtrId); void GetNextCompareInfo(TTDCompareTag* tag, TTD_PTR_ID* h1PtrId, TTD_PTR_ID* h2PtrId); void GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, const NSSnapValues::SlotArrayInfo** val1, TTD_PTR_ID h2PtrId, const NSSnapValues::SlotArrayInfo** val2); void GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, const NSSnapValues::ScriptFunctionScopeInfo** val1, TTD_PTR_ID h2PtrId, const NSSnapValues::ScriptFunctionScopeInfo** val2); void GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, uint64* val1, TTD_PTR_ID h2PtrId, uint64* val2); void GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, const NSSnapValues::FunctionBodyResolveInfo** val1, TTD_PTR_ID h2PtrId, const NSSnapValues::FunctionBodyResolveInfo** val2); void GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, const NSSnapObjects::SnapObject** val1, TTD_PTR_ID h2PtrId, const NSSnapObjects::SnapObject** val2); }; #endif } #endif