void TTDCompareMap::GetNextCompareInfo(TTDCompareTag* tag, TTD_PTR_ID* h1PtrId, TTD_PTR_ID* h2PtrId) { if(this->H1PtrIdWorklist.Empty()) { *tag = TTDCompareTag::Done; *h1PtrId = TTD_INVALID_PTR_ID; *h2PtrId = TTD_INVALID_PTR_ID; } else { *h1PtrId = this->H1PtrIdWorklist.Dequeue(); *h2PtrId = this->H1PtrToH2PtrMap.Item(*h1PtrId); this->CurrentPath = this->H1PtrToPathMap.Item(*h1PtrId); this->CurrentH1Ptr = *h1PtrId; this->CurrentH2Ptr = *h2PtrId; if(this->H1SlotArrayMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2SlotArrayMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::SlotArray; } else if(this->H1FunctionScopeInfoMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2FunctionScopeInfoMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::FunctionScopeInfo; } else if(this->H1FunctionTopLevelLoadMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2FunctionTopLevelLoadMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::TopLevelLoadFunction; } else if(this->H1FunctionTopLevelNewMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2FunctionTopLevelNewMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::TopLevelNewFunction; } else if(this->H1FunctionTopLevelEvalMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2FunctionTopLevelEvalMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::TopLevelEvalFunction; } else if(this->H1FunctionBodyMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2FunctionBodyMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::FunctionBody; } else if(this->H1ObjectMap.ContainsKey(*h1PtrId)) { this->DiagnosticAssert(this->H2ObjectMap.ContainsKey(*h2PtrId)); *tag = TTDCompareTag::SnapObject; } else { TTDAssert(!this->H1ValueMap.ContainsKey(*h1PtrId), "Should be comparing by value!!!"); TTDAssert(false, "Id not found in any of the maps!!!"); *tag = TTDCompareTag::Done; } } }
void ScriptContextTTD::GetFromAsyncPendingList(TTDPendingAsyncBufferModification* pendingInfo, byte* finalModPos) { pendingInfo->ArrayBufferVar = nullptr; pendingInfo->Index = 0; const byte* currentBegin = nullptr; int32 pos = -1; for(int32 i = 0; i < this->m_ttdPendingAsyncModList.Count(); ++i) { const TTDPendingAsyncBufferModification& pi = this->m_ttdPendingAsyncModList.Item(i); const Js::ArrayBuffer* pbuff = Js::ArrayBuffer::FromVar(pi.ArrayBufferVar); const byte* pbuffBegin = pbuff->GetBuffer() + pi.Index; const byte* pbuffMax = pbuff->GetBuffer() + pbuff->GetByteLength(); //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 if(pbuffBegin > finalModPos || pbuffMax < finalModPos) { continue; } //it is in the right range so now we assume non-overlapping so we see if this pbuffBegin is closer than the current best TTDAssert(finalModPos != currentBegin, "We have something strange!!!"); if(currentBegin == nullptr || finalModPos < currentBegin) { currentBegin = pbuffBegin; pos = (int32)i; } } TTDAssert(pos != -1, "Missing matching register!!!"); *pendingInfo = this->m_ttdPendingAsyncModList.Item(pos); this->m_ttdPendingAsyncModList.RemoveAt(pos); }
Js::FunctionBody* RuntimeContextInfo::LookupKnownFunctionBodyFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const { int32 pos = LookupPositionInDictNameList<Js::FunctionBody*, true>(pathIdString, this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString); TTDAssert(pos != -1, "Missing function."); return (pos != -1) ? this->m_sortedFunctionBodyList.Item(pos) : nullptr; }
void BoundFunction::ProcessCorePaths() { this->GetScriptContext()->TTDWellKnownInfo->EnqueueNewPathVarAsNeeded(this, this->targetFunction, _u("!targetFunction")); this->GetScriptContext()->TTDWellKnownInfo->EnqueueNewPathVarAsNeeded(this, this->boundThis, _u("!boundThis")); TTDAssert(this->count == 0, "Should only have empty args in core image"); }
void RuntimeContextInfo::EnqueueNewPathVarAsNeeded(Js::RecyclableObject* parent, Js::Var val, const char16* propName, const char16* optacessortag) { if(JsSupport::IsVarTaggedInline(val)) { return; } if(JsSupport::IsVarPrimitiveKind(val) && !Js::GlobalObject::Is(parent)) { 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. } Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(val); if(!this->m_coreObjToPathMap.ContainsKey(obj)) { const UtilSupport::TTAutoString* ppath = this->m_coreObjToPathMap.Item(parent); this->m_worklist.Enqueue(obj); UtilSupport::TTAutoString* tpath = TT_HEAP_NEW(UtilSupport::TTAutoString, *ppath); tpath->Append(_u(".")); tpath->Append(propName); if(optacessortag != nullptr) { tpath->Append(optacessortag); } TTDAssert(!this->m_coreObjToPathMap.ContainsKey(obj), "Already in map!!!"); this->m_coreObjToPathMap.AddNew(obj, tpath); } }
uint32 JsrtRuntime::BPRegister_TTD(int64 bpID, Js::ScriptContext* scriptContext, Js::Utf8SourceInfo* utf8SourceInfo, uint32 line, uint32 column, BOOL* isNewBP) { TTDAssert(this->jsrtDebugManager != nullptr, "This needs to be setup before registering any breakpoints."); Js::BreakpointProbe* probe = this->jsrtDebugManager->SetBreakpointHelper_TTD(bpID, scriptContext, utf8SourceInfo, line, column, isNewBP); return probe->GetId(); }
Js::DebuggerScope* RuntimeContextInfo::LookupKnownDebuggerScopeFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const { int32 pos = LookupPositionInDictNameList<Js::DebuggerScope*, true>(pathIdString, this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString); TTDAssert(pos != -1, "Missing debug scope."); return (pos != -1) ? this->m_sortedDbgScopeList.Item(pos) : nullptr; }
Js::RecyclableObject* RuntimeContextInfo::LookupKnownObjectFromPath(TTD_WELLKNOWN_TOKEN pathIdString) const { int32 pos = LookupPositionInDictNameList<Js::RecyclableObject*, true>(pathIdString, this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString); TTDAssert(pos != -1, "This isn't a well known object!"); return this->m_sortedObjectList.Item(pos); }
void InflateMap::PrepForReInflate(uint32 ctxCount, uint32 handlerCount, uint32 typeCount, uint32 objectCount, uint32 bodyCount, uint32 dbgScopeCount, uint32 envCount, uint32 slotCount) { this->m_typeMap.Initialize(typeCount); this->m_handlerMap.Initialize(handlerCount); this->m_tagToGlobalObjectMap.Initialize(ctxCount); this->m_debuggerScopeHomeBodyMap.Initialize(dbgScopeCount); this->m_debuggerScopeChainIndexMap.Initialize(dbgScopeCount); this->m_environmentMap.Initialize(envCount); this->m_slotArrayMap.Initialize(slotCount); this->m_promiseDataMap.Clear(); //We re-use these values (and reset things below) so we don't neet to initialize them here //m_objectMap //m_functionBodyMap //copy info we want to reuse into the old maps this->m_oldObjectMap.MoveDataInto(this->m_objectMap); this->m_oldFunctionBodyMap.MoveDataInto(this->m_functionBodyMap); //allocate the old pin set and fill it TTDAssert(this->m_oldInflatePinSet == nullptr, "Old pin set is not null."); Recycler* pinRecycler = this->m_inflatePinSet->GetAllocator(); this->m_oldInflatePinSet.Root(RecyclerNew(pinRecycler, ObjectPinSet, pinRecycler, this->m_inflatePinSet->Count()), pinRecycler); for(auto iter = this->m_inflatePinSet->GetIterator(); iter.IsValid(); iter.MoveNext()) { this->m_oldInflatePinSet->AddNew(iter.CurrentKey()); } this->m_inflatePinSet->Clear(); this->m_environmentPinSet->Clear(); this->m_slotArrayPinSet->Clear(); }
Var JavascriptExternalFunction::HandleRecordReplayExternalFunction_Thunk(Js::JavascriptFunction* function, CallInfo& callInfo, Arguments& args, ScriptContext* scriptContext) { JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); Var result = nullptr; if(scriptContext->ShouldPerformReplayAction()) { TTD::TTDNestingDepthAutoAdjuster logPopper(scriptContext->GetThreadContext()); scriptContext->GetThreadContext()->TTDLog->ReplayExternalCallEvent(externalFunction, args, &result); } else { TTDAssert(scriptContext->ShouldPerformRecordAction(), "Check either record/replay before calling!!!"); TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog; TTD::TTDNestingDepthAutoAdjuster logPopper(scriptContext->GetThreadContext()); TTD::NSLogEvents::EventLogEntry* callEvent = elog->RecordExternalCallEvent(externalFunction, scriptContext->GetThreadContext()->TTDRootNestingCount, args, false); BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) { // Don't do stack probe since BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION does that for us already result = externalFunction->nativeMethod(function, callInfo, args.Values); } END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext); //Exceptions should be prohibited so no need to do extra work elog->RecordExternalCallEvent_Complete(externalFunction, callEvent, result); } return result; }
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) { TTDAssert(topLevelScriptLoad.Count() == 0 && topLevelNewFunction.Count() == 0 && topLevelEval.Count() == 0, "Should be empty when you call this."); for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext()) { Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body)) { topLevelScriptLoad.Add(iter.CurrentValue()); } } for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext()) { Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body)) { topLevelNewFunction.Add(iter.CurrentValue()); } } for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext()) { Js::FunctionBody* body = TTD_COERCE_PTR_ID_TO_FUNCTIONBODY(iter.CurrentValue().ContextSpecificBodyPtrId); if(onlyLiveTopLevelBodies == nullptr || onlyLiveTopLevelBodies->Contains(body)) { topLevelEval.Add(iter.CurrentValue()); } } }
void ThreadContextTTD::AddNewScriptContext_Helper(Js::ScriptContext* ctx, HostScriptContextCallbackFunctor& callbackFunctor, bool noNative, bool debugMode) { //// //First just setup the standard things needed for a script context ctx->TTDHostCallbackFunctor = callbackFunctor; if(noNative) { ctx->ForceNoNative(); } if(debugMode) { #ifdef _WIN32 ctx->InitializeDebugging(); #else // //TODO: x-plat does not like some parts of initiallize debugging so just set the flag we need // ctx->GetDebugContext()->SetDebuggerMode(Js::DebuggerMode::Debugging); #endif } ctx->InitializeCoreImage_TTD(); TTDAssert(!this->m_contextList.Contains(ctx), "We should only be adding at creation time!!!"); this->m_contextList.Add(ctx); }
void TTDComparePath::WritePathToConsole(ThreadContext* threadContext, bool printNewline, char16* namebuff) const { if(this->m_prefix != nullptr) { this->m_prefix->WritePathToConsole(threadContext, false, namebuff); } if(this->m_stepKind == StepKind::PropertyData || this->m_stepKind == StepKind::PropertyGetter || this->m_stepKind == StepKind::PropertySetter) { const Js::PropertyRecord* pRecord = threadContext->GetPropertyName((Js::PropertyId)this->m_step.IndexOrPID); js_memcpy_s(namebuff, 256 * sizeof(char16), pRecord->GetBuffer(), pRecord->GetLength() * sizeof(char16)); namebuff[pRecord->GetLength()] = _u('\0'); } bool isFirst = (this->m_prefix == nullptr); switch(this->m_stepKind) { case StepKind::Empty: break; case StepKind::Root: wprintf(_u("root#%I64i"), this->m_step.IndexOrPID); break; case StepKind::PropertyData: wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::PropertyGetter: wprintf(_u("%ls<%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::PropertySetter: wprintf(_u("%ls>%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::Array: wprintf(_u("[%I64i]"), this->m_step.IndexOrPID); break; case StepKind::Scope: wprintf(_u("%ls_scope[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID); break; case StepKind::SlotArray: wprintf(_u("%ls_slots[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID); break; case StepKind::FunctionBody: wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName); break; case StepKind::Special: wprintf(_u("%ls_%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName); break; case StepKind::SpecialArray: wprintf(_u("%ls_%ls[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.OptName, this->m_step.IndexOrPID); break; default: TTDAssert(false, "Unknown tag in switch statement!!!"); break; } if(printNewline) { wprintf(_u("\n")); } }
bool DynamicObjectPropertyEnumerator::CanUseJITFastPath() const { #if ENABLE_TTD TTDAssert(this->cachedData == nullptr || !this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode(), "We should always have cachedData null if we are in record or replay mode"); #endif return !this->IsNullEnumerator() && !GetEnumNonEnumerable() && this->cachedData != nullptr; }
Var __stdcall JavascriptExternalFunction::TTDReplayDummyExternalMethod(Var callee, Var *args, USHORT cargs, StdCallJavascriptMethodInfo *info, void *callbackState) { JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(callee); ScriptContext* scriptContext = externalFunction->type->GetScriptContext(); TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog; TTDAssert(elog != nullptr, "How did this get created then???"); //If this flag is set then this is ok (the debugger may be evaluating this so just return undef -- otherwise this is an error if(!elog->IsDebugModeFlagSet()) { TTDAssert(false, "This should never be reached in pure replay mode!!!"); return nullptr; } return scriptContext->GetLibrary()->GetUndefined(); }
void RuntimeContextInfo::LoadAndOrderPropertyNames(Js::RecyclableObject* obj, JsUtil::List<const Js::PropertyRecord*, HeapAllocator>& propertyList) { TTDAssert(propertyList.Count() == 0, "This should be empty."); Js::ScriptContext* ctx = obj->GetScriptContext(); uint32 propcount = (uint32)obj->GetPropertyCount(); //get all of the properties for(uint32 i = 0; i < propcount; ++i) { Js::PropertyIndex propertyIndex = (Js::PropertyIndex)i; Js::PropertyId propertyId = obj->GetPropertyId(propertyIndex); if((propertyId != Js::Constants::NoProperty) & (!Js::IsInternalPropertyId(propertyId))) { TTDAssert(obj->HasOwnProperty(propertyId), "We are assuming this is own property count."); propertyList.Add(ctx->GetPropertyName(propertyId)); } } //now sort the list so the traversal order is stable //Rock a custom shell sort!!!! const int32 gaps[6] = { 132, 57, 23, 10, 4, 1 }; int32 llen = propertyList.Count(); for(uint32 gapi = 0; gapi < 6; ++gapi) { int32 gap = gaps[gapi]; for(int32 i = gap; i < llen; i++) { const Js::PropertyRecord* temp = propertyList.Item(i); int32 j = 0; for(j = i; j >= gap && PropertyNameCmp(propertyList.Item(j - gap), temp); j -= gap) { const Js::PropertyRecord* shiftElem = propertyList.Item(j - gap); propertyList.SetItem(j, shiftElem); } propertyList.SetItem(j, temp); } } }
void RuntimeContextInfo::EnqueueRootPathObject(const char16* rootName, Js::RecyclableObject* obj) { this->m_worklist.Enqueue(obj); UtilSupport::TTAutoString* rootStr = TT_HEAP_NEW(UtilSupport::TTAutoString, rootName); TTDAssert(!this->m_coreObjToPathMap.ContainsKey(obj), "Already in map!!!"); this->m_coreObjToPathMap.AddNew(obj, rootStr); }
void HeapArgumentsObject::ExtractSnapObjectDataInto_Helper(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) { TTD::NSSnapObjects::SnapHeapArgumentsInfo* argsInfo = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapHeapArgumentsInfo>(); TTDAssert(this->callerDeleted == 0, "This never seems to be set but I want to assert just to be safe."); argsInfo->NumOfArguments = this->numOfArguments; argsInfo->FormalCount = this->formalCount; uint32 depOnCount = 0; TTD_PTR_ID* depOnArray = nullptr; argsInfo->IsFrameNullPtr = false; argsInfo->FrameObject = TTD_INVALID_PTR_ID; if(this->frameObject == nullptr) { argsInfo->IsFrameNullPtr = true; } else { argsInfo->FrameObject = TTD_CONVERT_VAR_TO_PTR_ID(this->frameObject); //Primitive kinds always inflated first so we only need to deal with complex kinds as depends on if(TTD::JsSupport::IsVarComplexKind(this->frameObject)) { depOnCount = 1; depOnArray = alloc.SlabAllocateArray<TTD_PTR_ID>(depOnCount); depOnArray[0] = argsInfo->FrameObject; } } argsInfo->DeletedArgFlags = (this->formalCount != 0) ? alloc.SlabAllocateArrayZ<byte>(argsInfo->FormalCount) : nullptr; if(this->deletedArgs != nullptr) { for(uint32 i = 0; i < this->formalCount; ++i) { if(this->deletedArgs->Test(i)) { argsInfo->DeletedArgFlags[i] = true; } } } if(depOnCount == 0) { TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapHeapArgumentsInfo*, argsKind>(objData, argsInfo); } else { TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapHeapArgumentsInfo*, argsKind>(objData, argsInfo, alloc, depOnCount, depOnArray); } }
void TTDCompareMap::DiagnosticAssert(bool condition) { if(!condition) { if(this->CurrentPath != nullptr) { wprintf(_u("Snap1 ptrid: *0x%I64x\n"), this->CurrentH1Ptr); wprintf(_u("Snap2 ptrid: *0x%I64x\n"), this->CurrentH2Ptr); this->CurrentPath->WritePathToConsole(this->Context, true, this->PathBuffer); } } TTDAssert(condition, "Diagnostic compare assertion failed!!!"); }
Var JavascriptExternalFunction::HandleRecordReplayExternalFunction_StdThunk(Js::RecyclableObject* function, CallInfo& callInfo, Arguments& args, ScriptContext* scriptContext) { JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); Var result = nullptr; if(scriptContext->ShouldPerformReplayAction()) { TTD::TTDNestingDepthAutoAdjuster logPopper(scriptContext->GetThreadContext()); scriptContext->GetThreadContext()->TTDLog->ReplayExternalCallEvent(externalFunction, args, &result); } else { if (args.Info.Count > USHORT_MAX) { // Due to compat reasons, stdcall external functions expect a ushort count of args. // To support more than this we will need a new API. Js::JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgListTooLarge); } TTDAssert(scriptContext->ShouldPerformRecordAction(), "Check either record/replay before calling!!!"); TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog; TTD::TTDNestingDepthAutoAdjuster logPopper(scriptContext->GetThreadContext()); TTD::NSLogEvents::EventLogEntry* callEvent = elog->RecordExternalCallEvent(externalFunction, scriptContext->GetThreadContext()->TTDRootNestingCount, args, true); StdCallJavascriptMethodInfo info = { args[0], args.HasNewTarget() ? args.GetNewTarget() : args.IsNewCall() ? function : scriptContext->GetLibrary()->GetUndefined(), args.IsNewCall() }; BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, args.Values, static_cast<ushort>(args.Info.Count), &info, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); elog->RecordExternalCallEvent_Complete(externalFunction, callEvent, result); } return result; }
void ScriptContextTTD::ProcessFunctionBodyOnUnLoad(Js::FunctionBody* body, Js::FunctionBody* parent) { //if this is a root (parent is null) then put this in the rootbody pin set so it isn't reclaimed on us if(parent == nullptr) { TTDAssert(this->m_ttdPinnedRootFunctionSet->Contains(body), "We already added this function!!!"); this->m_ttdPinnedRootFunctionSet->Remove(body); } this->m_ttdFunctionBodyParentMap.Remove(body); for(uint32 i = 0; i < body->GetNestedCount(); ++i) { Js::ParseableFunctionInfo* pfiMid = body->GetNestedFunctionForExecution(i); Js::FunctionBody* currfb = TTD::JsSupport::ForceAndGetFunctionBody(pfiMid); this->ProcessFunctionBodyOnUnLoad(currfb, body); } }
void InflateMap::UpdateFBScopes(const NSSnapValues::SnapFunctionBodyScopeChain& scopeChainInfo, Js::FunctionBody* fb) { TTDAssert((int32)scopeChainInfo.ScopeCount == (fb->GetScopeObjectChain() != nullptr ? fb->GetScopeObjectChain()->pScopeChain->Count() : 0), "Mismatch in scope counts!!!"); if(fb->GetScopeObjectChain() != nullptr) { Js::ScopeObjectChain* scChain = fb->GetScopeObjectChain(); for(int32 i = 0; i < scChain->pScopeChain->Count(); ++i) { TTD_PTR_ID dbgScopeId = scopeChainInfo.ScopeArray[i]; if(!this->m_debuggerScopeHomeBodyMap.Contains(dbgScopeId)) { this->m_debuggerScopeHomeBodyMap.AddItem(dbgScopeId, fb); this->m_debuggerScopeChainIndexMap.AddItem(dbgScopeId, i); } } } }
void TTDCompareMap::GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, uint64* val1, TTD_PTR_ID h2PtrId, uint64* val2) { if(compareTag == TTDCompareTag::TopLevelLoadFunction) { *val1 = this->H1FunctionTopLevelLoadMap.Item(h1PtrId); *val2 = this->H2FunctionTopLevelLoadMap.Item(h2PtrId); } else if(compareTag == TTDCompareTag::TopLevelNewFunction) { *val1 = this->H1FunctionTopLevelNewMap.Item(h1PtrId); *val2 = this->H2FunctionTopLevelNewMap.Item(h2PtrId); } else { TTDAssert(compareTag == TTDCompareTag::TopLevelEvalFunction, "Should be a type"); *val1 = this->H1FunctionTopLevelEvalMap.Item(h1PtrId); *val2 = this->H2FunctionTopLevelEvalMap.Item(h2PtrId); } }
uint32 ScriptContextTTD::FindTopLevelCtrForBody(Js::FunctionBody* body) const { Js::FunctionBody* rootBody = body; while(this->ResolveParentBody(rootBody) != nullptr) { rootBody = this->ResolveParentBody(rootBody); } TTD_PTR_ID trgtid = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(rootBody); for(auto iter = this->m_ttdTopLevelScriptLoad.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid) { return iter.CurrentValue().TopLevelBodyCtr; } } for(auto iter = this->m_ttdTopLevelNewFunction.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid) { return iter.CurrentValue().TopLevelBodyCtr; } } for(auto iter = this->m_ttdTopLevelEval.GetIterator(); iter.IsValid(); iter.MoveNext()) { if(iter.CurrentValue().ContextSpecificBodyPtrId == trgtid) { return iter.CurrentValue().TopLevelBodyCtr; } } TTDAssert(false, "We are missing a top-level function reference."); return 0; }
void RuntimeContextInfo::GatherKnownObjectToPathMap(Js::ScriptContext* ctx) { JsUtil::List<const Js::PropertyRecord*, HeapAllocator> propertyRecordList(&HeapAllocator::Instance); this->EnqueueRootPathObject(_u("global"), ctx->GetGlobalObject()); this->EnqueueRootPathObject(_u("null"), ctx->GetLibrary()->GetNull()); this->EnqueueRootPathObject(_u("undeclBlockVar"), Js::RecyclableObject::FromVar(ctx->GetLibrary()->GetUndeclBlockVar())); this->EnqueueRootPathObject(_u("_defaultAccessor"), ctx->GetLibrary()->GetDefaultAccessorFunction()); if(ctx->GetConfig()->IsErrorStackTraceEnabled()) { this->EnqueueRootPathObject(_u("_stackTraceAccessor"), ctx->GetLibrary()->GetStackTraceAccessorFunction()); } this->EnqueueRootPathObject(_u("_throwTypeErrorRestrictedPropertyAccessor"), ctx->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction()); if(ctx->GetConfig()->IsES6PromiseEnabled()) { this->EnqueueRootPathObject(_u("_identityFunction"), ctx->GetLibrary()->GetIdentityFunction()); this->EnqueueRootPathObject(_u("_throwerFunction"), ctx->GetLibrary()->GetThrowerFunction()); } // ArrayIteratorPrototype is not created when we have JsBuiltins, it it created on-demand only #ifdef ENABLE_JS_BUILTINS if (ctx->IsJsBuiltInEnabled()) { ctx->GetLibrary()->EnsureBuiltInEngineIsReady(); } #endif this->EnqueueRootPathObject(_u("_arrayIteratorPrototype"), ctx->GetLibrary()->GetArrayIteratorPrototype()); this->EnqueueRootPathObject(_u("_mapIteratorPrototype"), ctx->GetLibrary()->GetMapIteratorPrototype()); this->EnqueueRootPathObject(_u("_setIteratorPrototype"), ctx->GetLibrary()->GetSetIteratorPrototype()); this->EnqueueRootPathObject(_u("_stringIteratorPrototype"), ctx->GetLibrary()->GetStringIteratorPrototype()); this->EnqueueRootPathObject(_u("_generatorNextFunction"), ctx->GetLibrary()->EnsureGeneratorNextFunction()); this->EnqueueRootPathObject(_u("_generatorReturnFunction"), ctx->GetLibrary()->EnsureGeneratorReturnFunction()); this->EnqueueRootPathObject(_u("_generatorThrowFunction"), ctx->GetLibrary()->EnsureGeneratorThrowFunction()); this->EnqueueRootPathObject(_u("_generatorFunctionConstructor"), ctx->GetLibrary()->GetGeneratorFunctionConstructor()); this->EnqueueRootPathObject(_u("_asyncFunctionConstructor"), ctx->GetLibrary()->GetAsyncFunctionConstructor()); uint32 counter = 0; while(!this->m_worklist.Empty()) { Js::RecyclableObject* curr = this->m_worklist.Dequeue(); counter++; //// //Handle the standard properties for all object types //load propArray with all property names propertyRecordList.Clear(); LoadAndOrderPropertyNames(curr, propertyRecordList); //access each property and process the target objects as needed for(int32 i = 0; i < propertyRecordList.Count(); ++i) { const Js::PropertyRecord* precord = propertyRecordList.Item(i); Js::Var getter = nullptr; Js::Var setter = nullptr; if(curr->GetAccessors(precord->GetPropertyId(), &getter, &setter, ctx)) { if(getter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(getter)) { TTDAssert(Js::JavascriptFunction::Is(getter), "The getter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, getter, precord, _u(">")); } if(setter != nullptr && !Js::JavascriptOperators::IsUndefinedObject(setter)) { TTDAssert(Js::JavascriptFunction::Is(setter), "The setter is not a function?"); this->EnqueueNewPathVarAsNeeded(curr, Js::RecyclableObject::FromVar(setter), precord, _u("<")); } } else { Js::Var pitem = nullptr; BOOL isproperty = Js::JavascriptOperators::GetOwnProperty(curr, precord->GetPropertyId(), &pitem, ctx, nullptr); TTDAssert(isproperty, "Not sure what went wrong."); this->EnqueueNewPathVarAsNeeded(curr, pitem, precord, nullptr); } } //shouldn't have any dynamic array valued properties if(Js::DynamicType::Is(curr->GetTypeId())) { Js::ArrayObject* parray = Js::DynamicObject::FromVar(curr)->GetObjectArray(); if(parray != nullptr) { this->EnqueueNewPathVarAsNeeded(curr, parray, _u("_object_array_")); } } Js::RecyclableObject* proto = curr->GetPrototype(); bool skipProto = (proto == nullptr) || Js::JavascriptOperators::IsUndefinedOrNullType(proto->GetTypeId()); if(!skipProto) { this->EnqueueNewPathVarAsNeeded(curr, proto, _u("_proto_")); } curr->ProcessCorePaths(); } SortDictIntoListOnNames<Js::RecyclableObject*>(this->m_coreObjToPathMap, this->m_sortedObjectList, this->m_nullString); SortDictIntoListOnNames<Js::FunctionBody*>(this->m_coreBodyToPathMap, this->m_sortedFunctionBodyList, this->m_nullString); SortDictIntoListOnNames<Js::DebuggerScope*>(this->m_coreDbgScopeToPathMap, this->m_sortedDbgScopeList, this->m_nullString); }
void RecyclableObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) { TTDAssert(false, "Missing subtype implementation."); }
void TTDCompareMap::GetCompareValues(TTDCompareTag compareTag, TTD_PTR_ID h1PtrId, const NSSnapObjects::SnapObject** val1, TTD_PTR_ID h2PtrId, const NSSnapObjects::SnapObject** val2) { TTDAssert(compareTag == TTDCompareTag::SnapObject, "Should be a type"); *val1 = this->H1ObjectMap.Item(h1PtrId); *val2 = this->H2ObjectMap.Item(h2PtrId); }
void ThreadContextTTD::SetActiveScriptContext(Js::ScriptContext* ctx) { TTDAssert(ctx == nullptr || this->m_contextList.Contains(ctx), "Missing value!!!"); this->m_activeContext = ctx; }
void JsrtRuntime::BPClearDocument_TTD() { TTDAssert(this->jsrtDebugManager != nullptr, "This needs to be setup before deleting any breakpoints."); this->jsrtDebugManager->ClearBreakpointDebugDocumentDictionary(); }
void JsrtRuntime::BPDelete_TTD(uint32 bpID) { TTDAssert(this->jsrtDebugManager != nullptr, "This needs to be setup before deleting any breakpoints."); this->jsrtDebugManager->GetDebugDocumentManager()->RemoveBreakpoint(bpID); }