예제 #1
0
    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;
            }
        }
    }
예제 #2
0
    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);
    }
예제 #3
0
    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;
    }
예제 #4
0
    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");
    }
예제 #5
0
    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);
        }
    }
예제 #6
0
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();
}
예제 #7
0
    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;
    }
예제 #8
0
    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);
    }
예제 #9
0
    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;
    }
예제 #11
0
    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());
            }
        }
    }
예제 #12
0
    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);
    }
예제 #13
0
    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();
    }
예제 #16
0
    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);
            }
        }
    }
예제 #17
0
    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);
    }
예제 #18
0
    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);
        }
    }
예제 #19
0
    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;
    }
예제 #21
0
    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);
        }
    }
예제 #22
0
    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);
                }
            }
        }
    }
예제 #23
0
 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);
     }
 }
예제 #24
0
    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;
    }
예제 #25
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);
    }
예제 #26
0
 void RecyclableObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
 {
     TTDAssert(false, "Missing subtype implementation.");
 }
예제 #27
0
 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);
 }
예제 #28
0
    void ThreadContextTTD::SetActiveScriptContext(Js::ScriptContext* ctx)
    {
        TTDAssert(ctx == nullptr || this->m_contextList.Contains(ctx), "Missing value!!!");

        this->m_activeContext = ctx;
    }
예제 #29
0
void JsrtRuntime::BPClearDocument_TTD()
{
    TTDAssert(this->jsrtDebugManager != nullptr, "This needs to be setup before deleting any breakpoints.");

    this->jsrtDebugManager->ClearBreakpointDebugDocumentDictionary();
}
예제 #30
0
void JsrtRuntime::BPDelete_TTD(uint32 bpID)
{
    TTDAssert(this->jsrtDebugManager != nullptr, "This needs to be setup before deleting any breakpoints.");

    this->jsrtDebugManager->GetDebugDocumentManager()->RemoveBreakpoint(bpID);
}