Ejemplo n.º 1
0
    void DebugManager::UpdateConsoleScope(DynamicObject* copyFromScope, ScriptContext* scriptContext)
    {
        Assert(copyFromScope != nullptr);
        DynamicObject* consoleScope = this->GetConsoleScope(scriptContext);
        Js::RecyclableObject* recyclableObject = Js::RecyclableObject::FromVar(copyFromScope);

        ulong newPropCount = recyclableObject->GetPropertyCount();
        for (ulong i = 0; i < newPropCount; i++)
        {
            Js::PropertyId propertyId = recyclableObject->GetPropertyId((Js::PropertyIndex)i);
            // For deleted properties we won't have a property id
            if (propertyId != Js::Constants::NoProperty)
            {
                Js::PropertyValueInfo propertyValueInfo;
                Var propertyValue;
                BOOL gotPropertyValue = recyclableObject->GetProperty(recyclableObject, propertyId, &propertyValue, &propertyValueInfo, scriptContext);
                AssertMsg(gotPropertyValue, "DebugManager::UpdateConsoleScope Should have got valid value?");

                OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding property '%s'\n"), scriptContext->GetPropertyName(propertyId)->GetBuffer());

                BOOL updateSuccess = consoleScope->SetPropertyWithAttributes(propertyId, propertyValue, propertyValueInfo.GetAttributes(), &propertyValueInfo);
                AssertMsg(updateSuccess, "DebugManager::UpdateConsoleScope Unable to update property value. Am I missing a scenario?");
            }
        }

        OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Number of properties on console scope object after update are %d\n"), consoleScope->GetPropertyCount());
    }
Ejemplo n.º 2
0
/**
 * \brief This function is a callback for the start of an
 * 		  element during APIVSXML parsing.
 *
 * \param[in]	pData - Pointer to data structure to fill in
 * \param[in]	pElement - Pointer to element tag
 * \param[in]	pAttr - Pointer to attribute list
 * \return		STATUS_FAIL - Parsing of APIVSXML input file failed
 * 				STATUS_PASS - Parsing of APIVSXML input file was successful
 */
static void
inputXmlStartElement(void *pData, const char *pElement, const char **pAttr)
{
	// See if we have just started
	if (0 == s_depth)
	{
		// We are at the top, so the only valid line
		// is <APIVSXML>.  Ensure this is what we got
		if (STATUS_PASS == pCode_start(pData, pElement, pAttr))
		{
			s_depth++;
			OUTPUT_TRACE("inputXmlStartElement(): PASS");
		}
		else
		{
			OUTPUT_TRACE("inputXmlStartElement(): *** FAIL ***");
		}
	}
	else
	{
		// Parse the opening element
		if (STATUS_PASS == pCode_parseOpen(pData, pElement, pAttr))
		{
			s_depth++;
			OUTPUT_TRACE("inputXmlStartElement(): PASS");
		}
		else
		{
			OUTPUT_TRACE("inputXmlStartElement(): *** FAIL ***");
		}
	}
}
Ejemplo n.º 3
0
    void ProbeContainer::DispatchMutationBreakpoint(InterpreterHaltState* pHaltState)
    {
        Assert(pHaltState->stopType == STOP_MUTATIONBREAKPOINT);

        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchMutationBreakpoint: start: this=%p, pHaltState=%p\n"), this, pHaltState);
        if (!CanDispatchHalt(pHaltState))
        {
            return;
        }

        // will store Current offset of the bytecode block.
        int currentOffset = -1;

        __try
        {
            InitializeLocation(pHaltState);
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchMutationBreakpoint: initialized location: pHaltState=%p, pHaltState->IsValid()=%d\n"),
                pHaltState, pHaltState->IsValid());

            if (pHaltState->IsValid())
            {
                // For interpreter frames, change the current location pointer of bytecode block, as it might be pointing to the next statement on the body.
                // In order to generated proper binding of mutation statement, the bytecode offset needed to be on the same span of the statement.
                // For native frames the offset is always current.
                // Move back a single byte to ensure that it falls under on the same statement.
                if (pHaltState->topFrame->IsInterpreterFrame())
                {
                    currentOffset = pHaltState->GetCurrentOffset();
                    Assert(currentOffset > 0);
                    pHaltState->SetCurrentOffset(currentOffset - 1);
                }
                debugManager->stepController.Deactivate(pHaltState);
                debugManager->asyncBreakController.Deactivate();

                pHaltState->GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);

                Assert(pHaltState->GetFunction()->GetScriptContext() == pScriptContext);

                haltCallbackProbe->DispatchHalt(pHaltState);
            }
        }
        __finally
        {
            // Restore the current offset;
            if (currentOffset != -1 && pHaltState->topFrame->IsInterpreterFrame())
            {
                pHaltState->SetCurrentOffset(currentOffset);
            }
            DestroyLocation();
        }

    }
Ejemplo n.º 4
0
    DiagNativeStackFrame::DiagNativeStackFrame(
        ScriptFunction* function,
        int byteCodeOffset,
        void* stackAddr,
        void *codeAddr,
        int frameIndex) :
        DiagStackFrame(frameIndex),
        m_function(function),
        m_byteCodeOffset(byteCodeOffset),
        m_stackAddr(stackAddr),
        m_localVarSlotsOffset(InvalidOffset),
        m_localVarChangedOffset(InvalidOffset)
    {
        Assert(m_stackAddr != NULL);
        AssertMsg(m_function && m_function->GetScriptContext() && m_function->GetScriptContext()->IsInDebugMode(),
            "This only supports functions in debug mode.");

        FunctionEntryPointInfo * entryPointInfo = GetFunction()->GetEntryPointFromNativeAddress((DWORD_PTR)codeAddr);
        if (entryPointInfo)
        {
            m_localVarSlotsOffset = entryPointInfo->localVarSlotsOffset;
            m_localVarChangedOffset = entryPointInfo->localVarChangedOffset;
        }
        else
        {
            AssertMsg(FALSE, "Failed to get entry point for native address. Most likely the frame is old/gone.");
        }
        OUTPUT_TRACE(Js::DebuggerPhase, L"DiagNativeStackFrame::DiagNativeStackFrame: e.p(addr %p)=%p varOff=%d changedOff=%d\n", codeAddr, entryPointInfo, m_localVarSlotsOffset, m_localVarChangedOffset);
    }
Ejemplo n.º 5
0
    void ProbeContainer::DestroyLocation()
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DestroyLocation (start): this=%p, IsNextStatementChanged=%d, haltCallbackProbe=%p\n"),
            this, this->IsNextStatementChanged, haltCallbackProbe);

        if (IsNextStatementChanged)
        {
            Assert(bytecodeOffset != debugManager->stepController.byteOffset);
            // Note: when we dispatching an exception bytecodeOffset would be same as pProbeManager->pCurrentInterpreterLocation->GetCurrentOffset().

            debugManager->pCurrentInterpreterLocation->SetCurrentOffset(bytecodeOffset);
            IsNextStatementChanged = false;
        }

        framePointers = nullptr;

        // Reset the exception object.

        jsExceptionObject = nullptr;

        Assert(debugManager);
        debugManager->UnsetCurrentInterpreterLocation();

        pinnedPropertyRecords->Reset();

        // Guarding if the probe engine goes away when we are sitting at breakpoint.
        if (haltCallbackProbe)
        {
            // The clean up is called here to scriptengine's object to remove all DebugStackFrames
            haltCallbackProbe->CleanupHalt();
        }
    }
Ejemplo n.º 6
0
    void ProbeContainer::DispatchStepHandler(InterpreterHaltState* pHaltState, OpCode* pOriginalOpcode)
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchStepHandler: start: this=%p, pHaltState=%p, pOriginalOpcode=0x%x\n"), this, pHaltState, pOriginalOpcode);

        if (!CanDispatchHalt(pHaltState))
        {
            return;
        }

        __try
        {
            InitializeLocation(pHaltState);
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchStepHandler: initialized location: pHaltState=%p, pHaltState->IsValid()=%d\n"),
                pHaltState, pHaltState->IsValid());

            if (pHaltState->IsValid()) // Only proceed if we find a valid top frame and that is the executing function
            {
                if (debugManager->stepController.IsStepComplete(pHaltState, haltCallbackProbe, *pOriginalOpcode))
                {
                    OpCode oldOpcode = *pOriginalOpcode;
                    pHaltState->GetFunction()->ProbeAtOffset(pHaltState->GetCurrentOffset(), pOriginalOpcode);
                    pHaltState->GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);

                    debugManager->stepController.Deactivate(pHaltState);
                    haltCallbackProbe->DispatchHalt(pHaltState);

                    if (oldOpcode == OpCode::Break && debugManager->stepController.stepType == STEP_DOCUMENT)
                    {
                        // That means we have delivered the stepping to the debugger, where we had the breakpoint
                        // already, however it is possible that debugger can initiate the step_document. In that
                        // case debugger did not break due to break. So we have break as a breakpoint reason.
                        *pOriginalOpcode = OpCode::Break;
                    }
                    else if (OpCode::Break == *pOriginalOpcode)
                    {
                        debugManager->stepController.stepCompleteOnInlineBreakpoint = true;
                    }
                }
            }
        }
        __finally
        {
            DestroyLocation();
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchStepHandler: end: pHaltState=%p\n"), pHaltState);
    }
Ejemplo n.º 7
0
    void ProbeContainer::AsyncActivate(HaltCallback* haltCallback)
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("Async break activated\n"));
        InterlockedExchangePointer((PVOID*)&this->pAsyncHaltCallback, haltCallback);

        Assert(debugManager);
        debugManager->asyncBreakController.Activate(haltCallback);
    }
Ejemplo n.º 8
0
    void ProbeContainer::DispatchInlineBreakpoint(InterpreterHaltState* pHaltState)
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchInlineBreakpoint: start: this=%p, pHaltState=%p\n"), this, pHaltState);

        if (!CanDispatchHalt(pHaltState))
        {
            return;
        }

        Assert(pHaltState->stopType == STOP_INLINEBREAKPOINT);

        __try
        {
            InitializeLocation(pHaltState);
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchInlineBreakpoint: initialized location: pHaltState=%p, pHaltState->IsValid()=%d\n"),
                pHaltState, pHaltState->IsValid());

            Assert(pHaltState->IsValid());

            // The ByteCodeReader should be available at this point, but because of possibility of garbled frame, we shouldn't hit AV
            if (pHaltState->IsValid())
            {
#if DBG
                pHaltState->GetFunction()->MustBeInDebugMode();
#endif

                // an inline breakpoint is being dispatched deactivate other stopping controllers
                debugManager->stepController.Deactivate(pHaltState);
                debugManager->asyncBreakController.Deactivate();

                pHaltState->GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);

                haltCallbackProbe->DispatchHalt(pHaltState);
            }
        }
        __finally
        {
            DestroyLocation();
        }
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchInlineBreakpoint: end: pHaltState=%p\n"), pHaltState);
    }
Ejemplo n.º 9
0
/**
 * \brief This function is a callback for the end of an element during APIVSXML
 * parsing.
 *
 * \param[in]	pData - Pointer to data structure to fill in
 * \param[in]	pElement - Pointer to element tag
 * \return		STATUS_FAIL - Parsing of APIVSXML input file failed
 * 				STATUS_PASS - Parsing of APIVSXML input file was successful
 */
static void
inputXmlEndElement(void *pData, const char *pElement)
{
	// Parse the closing of the element
	if (STATUS_PASS == pCode_parseClose(pData, pElement))
	{
		s_depth--;
		OUTPUT_TRACE("inputXmlEndElement(): PASS");
	}
	else
	{
		OUTPUT_TRACE("inputXmlEndElement(): *** FAIL ***");
	}

	// See if we are processing the root
	if (0 == s_depth)
	{
		// We are processing what should be the colsing tag for </APIVSXML>
		pCode_end(pData, pElement);
	}
}
Ejemplo n.º 10
0
    Var CrossSite::ProfileThunk(RecyclableObject* callable, CallInfo callInfo, ...)
    {
        JavascriptFunction* function = JavascriptFunction::FromVar(callable);
        Assert(function->GetTypeId() == TypeIds_Function);
        Assert(function->GetEntryPoint() == CrossSite::ProfileThunk);
        RUNTIME_ARGUMENTS(args, callInfo);
        ScriptContext * scriptContext = function->GetScriptContext();
        // It is not safe to access the function body if the script context is not alive.
        scriptContext->VerifyAliveWithHostContext(!function->IsExternal(),
            scriptContext->GetThreadContext()->GetPreviousHostScriptContext());

        JavascriptMethod entryPoint;
        FunctionInfo *funcInfo = function->GetFunctionInfo();

        TTD_XSITE_LOG(callable->GetScriptContext(), "DefaultOrProfileThunk", callable);

#ifdef ENABLE_WASM
        if (WasmScriptFunction::Is(function))
        {
            AsmJsFunctionInfo* asmInfo = funcInfo->GetFunctionBody()->GetAsmJsFunctionInfo();
            Assert(asmInfo);
            if (asmInfo->IsWasmDeferredParse())
            {
                entryPoint = WasmLibrary::WasmDeferredParseExternalThunk;
            }
            else
            {
                entryPoint = Js::AsmJsExternalEntryPoint;
            }
        } else
#endif
        if (funcInfo->HasBody())
        {
#if ENABLE_DEBUG_CONFIG_OPTIONS
            char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
#endif
            entryPoint = ScriptFunction::FromVar(function)->GetEntryPointInfo()->jsMethod;
            if (funcInfo->IsDeferred() && scriptContext->IsProfiling())
            {
                // if the current entrypoint is deferred parse we need to update it appropriately for the profiler mode.
                entryPoint = Js::ScriptContext::GetProfileModeThunk(entryPoint);
            }
            OUTPUT_TRACE(Js::ScriptProfilerPhase, _u("CrossSite::ProfileThunk FunctionNumber : %s, Entrypoint : 0x%08X\n"), funcInfo->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer), entryPoint);
        }
        else
        {
            entryPoint = ProfileEntryThunk;
        }


        return CommonThunk(function, entryPoint, args);
    }
Ejemplo n.º 11
0
    void ProbeContainer::DispatchAsyncBreak(InterpreterHaltState* pHaltState)
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchAsyncBreak: start: this=%p, pHaltState=%p\n"), this, pHaltState);

        if (!this->pAsyncHaltCallback || !CanDispatchHalt(pHaltState))
        {
            return;
        }

        __try
        {
            InitializeLocation(pHaltState, /* We don't need to match script context, stop at any available script function */ false);
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchAsyncBreak: initialized location: pHaltState=%p, pHaltState->IsValid()=%d\n"),
                pHaltState, pHaltState->IsValid());

            if (pHaltState->IsValid())
            {
                // Activate the current haltCallback with asyncStepController.
                debugManager->asyncBreakController.Activate(this->pAsyncHaltCallback);
                if (debugManager->asyncBreakController.IsAtStoppingLocation(pHaltState))
                {
                    OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchAsyncBreak: IsAtStoppingLocation: pHaltState=%p\n"), pHaltState);

                    pHaltState->GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);

                    debugManager->stepController.Deactivate(pHaltState);
                    debugManager->asyncBreakController.DispatchAndReset(pHaltState);
                }
            }
        }
        __finally
        {
            DestroyLocation();
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchAsyncBreak: end: pHaltState=%p\n"), pHaltState);
    }
    //
    // Saves the profile to the WININET cache and returns the bytes written
    //
    uint SourceDynamicProfileManager::SaveToProfileCacheAndRelease(SourceContextInfo* info)
    {
        uint bytesWritten = 0;
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
        if(profileDataCache)
        {
            if(ShouldSaveToProfileCache(info))
            {
                OUTPUT_TRACE(Js::DynamicProfilePhase, L"Saving profile. Number of functions: %d Url: %s...\n", startupFunctions->Length(), info->url);

                bytesWritten = SaveToProfileCache();

                if(bytesWritten == 0)
                {
                    OUTPUT_TRACE(Js::DynamicProfilePhase, L"Profile saving FAILED\n");
                }
            }

            profileDataCache->Release();
            profileDataCache = nullptr;
        }
#endif
        return bytesWritten;
    }
Ejemplo n.º 13
0
    bool ProbeContainer::InitializeLocation(InterpreterHaltState* pHaltState, bool fMatchWithCurrentScriptContext)
    {
        Assert(debugManager);
        debugManager->SetCurrentInterpreterLocation(pHaltState);

        ArenaAllocator* pDiagArena = debugManager->GetDiagnosticArena()->Arena();

        UpdateFramePointers(fMatchWithCurrentScriptContext);
        pHaltState->framePointers = framePointers;
        pHaltState->stringBuilder = Anew(pDiagArena, StringBuilder<ArenaAllocator>, pDiagArena);

        if (pHaltState->framePointers->Count() > 0)
        {
            pHaltState->topFrame = pHaltState->framePointers->Peek(0);
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::InitializeLocation (end): this=%p, pHaltState=%p, fMatch=%d, topFrame=%p\n"),
            this, pHaltState, fMatchWithCurrentScriptContext, pHaltState->topFrame);

        return true;
    }
Ejemplo n.º 14
0
void WritePerfHint(PerfHints hint, Js::FunctionBody * functionBody, uint byteCodeOffset /*= Js::Constants::NoByteCodeOffset*/)
{
    Assert(functionBody);
    Assert(((uint)hint) < _countof(s_perfHintContainer));

    PerfHintItem item = s_perfHintContainer[(uint)hint];

    int level = CONFIG_FLAG(PerfHintLevel);
    Assert(level <= (int)PerfHintLevels::VERBOSE);

    if ((int)item.level <= level)
    {
        ULONG lineNumber = functionBody->GetLineNumber();
        LONG columnNumber = functionBody->GetColumnNumber();
        if (byteCodeOffset != Js::Constants::NoByteCodeOffset)
        {
            functionBody->GetLineCharOffset(byteCodeOffset, &lineNumber, &columnNumber, false /*canAllocateLineCache*/);

            // returned values are 0-based. Adjusting.
            lineNumber++;
            columnNumber++;
        }

        // We will print the short name.
        TCHAR shortName[255];
        Js::FunctionBody::GetShortNameFromUrl(functionBody->GetSourceName(), shortName, 255);

        OUTPUT_TRACE(Js::PerfHintPhase, _u("%s : %s {\n      Function : %s [%s @ %u, %u]\n  Consequences : %s\n    Suggestion : %s\n}\n"),
            item.isNotOptimized ? _u("Not optimized") : _u("Optimized"),
            item.description,
            functionBody->GetExternalDisplayName(),
            shortName,
            lineNumber,
            columnNumber,
            item.consequences,
            item.suggestion);
        Output::Flush();
    }
}
Ejemplo n.º 15
0
bool XDataAllocator::Alloc(ULONG_PTR functionStart, DWORD functionSize,
    ushort pdataCount, ushort xdataSize, SecondaryAllocation* allocation)
{
    XDataAllocation* xdata = static_cast<XDataAllocation*>(allocation);
    Assert(start != nullptr);
    Assert(current != nullptr);
    Assert(current >= start);
    Assert(xdataSize <= XDATA_SIZE);
    Assert(pdataCount == 1);

    // Allocate a new xdata entry
    if((End() - current) >= XDATA_SIZE)
    {
        xdata->address = current;
        current += XDATA_SIZE;
    } // try allocating from the free list
    else if(freeList)
    {
        auto entry = freeList;
        xdata->address = entry->address;
        this->freeList = entry->next;
        HeapDelete(entry);
    }
    else
    {
        xdata->address = nullptr;
        OUTPUT_TRACE(Js::XDataAllocatorPhase, _u("No space for XDATA.\n"));
    }

#ifndef _WIN32
    if (xdata->address)
    {
        ClearHead(xdata->address);  // mark empty .eh_frame
    }
#endif

    return xdata->address != nullptr;
}
Ejemplo n.º 16
0
//
// Log loop body load event to VTune 
//
void VTuneChakraProfile::LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopHeader* loopHeader, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
    if (isJitProfilingActive)
    {
        iJIT_Method_Load methodInfo;
        memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
        const char16* methodName = body->GetExternalDisplayName();
        size_t methodLength = wcslen(methodName);
        methodLength = min(methodLength, (size_t)UINT_MAX); // Just truncate if it is too big
        size_t length = methodLength * 3 + /* spaces */ 2 + _countof(LoopStr) + /*size of loop number*/ 10 + /*NULL*/ 1;
        utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
        if(utf8MethodName)
        {
            methodInfo.method_id = iJIT_GetNewMethodID();
            size_t len = utf8::EncodeInto(utf8MethodName, methodName, (charcount_t)methodLength);
            sprintf_s((char*)(utf8MethodName + len), length - len," %s %d", LoopStr, loopNumber + 1);
            methodInfo.method_name = (char*)utf8MethodName;
            methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
            methodInfo.method_size = (uint)entryPoint->GetCodeSize();        // Size in memory - Must be exact

            size_t urlLength  = 0;
            utf8char_t* utf8Url = GetUrl(body, &urlLength);
            methodInfo.source_file_name = (char*)utf8Url;

            iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);
            OUTPUT_TRACE(Js::ProfilerPhase, _u("Loop body load event: %s Loop %d\n"), methodName, loopNumber + 1);

            if(urlLength > 0)
            {
                HeapDeleteArray(urlLength, utf8Url);
            }
            HeapDeleteArray(length, utf8MethodName);
        }
    }
#endif
}
Ejemplo n.º 17
0
    void ProbeContainer::UpdateFramePointers(bool fMatchWithCurrentScriptContext)
    {
        ArenaAllocator* pDiagArena = debugManager->GetDiagnosticArena()->Arena();
        framePointers = Anew(pDiagArena, DiagStack, pDiagArena);

        JavascriptStackWalker walker(pScriptContext, !fMatchWithCurrentScriptContext, nullptr/*returnAddress*/, true/*forceFullWalk*/);
        DiagStack* tempFramePointers = Anew(pDiagArena, DiagStack, pDiagArena);
        const bool isLibraryFrameEnabledDebugger = IsLibraryStackFrameSupportEnabled();

        walker.WalkUntil([&](JavascriptFunction* func, ushort frameIndex) -> bool
        {
            if (isLibraryFrameEnabledDebugger || !func->IsLibraryCode())
            {
                DiagStackFrame* frm = nullptr;
                InterpreterStackFrame *interpreterFrame = walker.GetCurrentInterpreterFrame();
                ScriptContext* frameScriptContext = walker.GetCurrentScriptContext();
                Assert(frameScriptContext);

                if (!fMatchWithCurrentScriptContext && !frameScriptContext->IsScriptContextInDebugMode() && tempFramePointers->Count() == 0)
                {
                    // this means the top frame is not in the debug mode. We shouldn't be stopping for this break.
                    // This could happen if the exception happens on the diagnosticsScriptEngine.
                    return true;
                }

                // Ignore frames which are not in debug mode, which can happen when diag engine calls into user engine under debugger
                // -- topmost frame is under debugger but some frames could be in non-debug mode as they are from diag engine.
                if (frameScriptContext->IsScriptContextInDebugMode() &&
                    (!fMatchWithCurrentScriptContext || frameScriptContext == pScriptContext))
                {
                    if (interpreterFrame)
                    {
                        frm = Anew(pDiagArena, DiagInterpreterStackFrame, interpreterFrame, frameIndex);
                    }
                    else
                    {
#if ENABLE_NATIVE_CODEGEN
                        if (func->IsScriptFunction())
                        {
                            frm = Anew(pDiagArena, DiagNativeStackFrame,
                                ScriptFunction::FromVar(walker.GetCurrentFunction()), walker.GetByteCodeOffset(), walker.GetCurrentArgv(), walker.GetCurrentCodeAddr(), frameIndex);
                        }
                        else
#else
                        Assert(!func->IsScriptFunction());
#endif
                        {
                            frm = Anew(pDiagArena, DiagRuntimeStackFrame, func, walker.GetCurrentNativeLibraryEntryName(), walker.GetCurrentArgv(), frameIndex);
                        }
                    }
                }

                if (frm)
                {
                    tempFramePointers->Push(frm);
                }
            }

            return false;
        });
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::UpdateFramePointers: detected %d frames (this=%p, fMatchWithCurrentScriptContext=%d)\n"),
            tempFramePointers->Count(), this, fMatchWithCurrentScriptContext);

        while (tempFramePointers->Count())
        {
            framePointers->Push(tempFramePointers->Pop());
        }
    }
Ejemplo n.º 18
0
//
// Log JIT method native load event to VTune 
//
void VTuneChakraProfile::LogMethodNativeLoadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
    if (isJitProfilingActive)
    {
        iJIT_Method_Load methodInfo;
        memset(&methodInfo, 0, sizeof(iJIT_Method_Load));
        const char16* methodName = body->GetExternalDisplayName();
        // Append function line number info to method name so that VTune can distinguish between polymorphic methods
        char16 methodNameBuffer[_MAX_PATH];
        ULONG lineNumber = body->GetLineNumber();
        char16 numberBuffer[20];
        _ltow_s(lineNumber, numberBuffer, 10);
        wcscpy_s(methodNameBuffer, methodName);
        if (entryPoint->GetJitMode() == ExecutionMode::SimpleJit)
        {
            wcscat_s(methodNameBuffer, _u(" Simple"));
        }
        wcscat_s(methodNameBuffer, _u(" {line:"));
        wcscat_s(methodNameBuffer, numberBuffer);
        wcscat_s(methodNameBuffer, _u("}"));

        size_t methodLength = wcslen(methodNameBuffer);
        Assert(methodLength < _MAX_PATH);
        size_t length = methodLength * 3 + 1;
        utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length);
        if (utf8MethodName)
        {
            methodInfo.method_id = iJIT_GetNewMethodID();
            utf8::EncodeIntoAndNullTerminate(utf8MethodName, methodNameBuffer, (charcount_t)methodLength);
            methodInfo.method_name = (char*)utf8MethodName;
            methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress();
            methodInfo.method_size = (uint)entryPoint->GetCodeSize();        // Size in memory - Must be exact

            LineNumberInfo numberInfo[1];

            uint lineCount = (entryPoint->GetNativeOffsetMapCount()) * 2 + 1; // may need to record both .begin and .end for all elements
            LineNumberInfo* pLineInfo = HeapNewNoThrowArray(LineNumberInfo, lineCount);

            if (pLineInfo == NULL || Js::Configuration::Global.flags.DisableVTuneSourceLineInfo)
            {
                // resort to original implementation, attribute all samples to first line
                numberInfo[0].LineNumber = lineNumber;
                numberInfo[0].Offset = 0;
                methodInfo.line_number_size = 1;
                methodInfo.line_number_table = numberInfo;
            }
            else
            {
                int size = entryPoint->PopulateLineInfo(pLineInfo, body);
                methodInfo.line_number_size = size;
                methodInfo.line_number_table = pLineInfo;
            }

            size_t urlLength = 0;
            utf8char_t* utf8Url = GetUrl(body, &urlLength);
            methodInfo.source_file_name = (char*)utf8Url;
            OUTPUT_TRACE(Js::ProfilerPhase, _u("Method load event: %s\n"), methodNameBuffer);
            iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo);

            HeapDeleteArray(lineCount, pLineInfo);

            if (urlLength > 0)
            {
                HeapDeleteArray(urlLength, utf8Url);
            }

            HeapDeleteArray(length, utf8MethodName);
        }
    }
#endif
}
Ejemplo n.º 19
0
    bool StepController::IsStepComplete(InterpreterHaltState* haltState, HaltCallback * haltCallback, OpCode originalOpcode)
    {
        int currentFrameCount = haltState->framePointers->Count();
        AssertMsg(currentFrameCount > 0, "In IsStepComplete we must have at least one frame.");

        FunctionBody* body = haltState->framePointers->Peek()->GetJavascriptFunction()->GetFunctionBody();
        bool canPossiblyHalt = haltCallback->CanHalt(haltState);

        OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(): stepType = %d "), stepType);

        uint scriptId = GetScriptId(body);
        AssertMsg(scriptId != InvalidScriptId, "scriptId cannot be 'invalid-reserved'");

        int byteOffset = haltState->GetCurrentOffset();
        bool fCanHalt = false;

        if (this->frameCountWhenSet > currentFrameCount && STEP_DOCUMENT != stepType)
        {
            // all steps match once the frame they started on has popped.
            fCanHalt = canPossiblyHalt;
        }
        else if (STEP_DOCUMENT == stepType)
        {
            OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(): docId when set=%d, currentDocId = %d, can Halt = %d, will halt = %d "), this->scriptIdWhenSet, scriptId, canPossiblyHalt, fCanHalt);
            fCanHalt = (scriptId != this->scriptIdWhenSet) && canPossiblyHalt;
        }
        else if (STEP_IN != stepType && this->frameCountWhenSet < currentFrameCount)
        {
            // Only step into allows the stack to be deeper
            OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(stepType = %d) returning false "), stepType);
            return false;
        }
        else if (STEP_OUT == stepType)
        {
            fCanHalt = this->frameCountWhenSet > currentFrameCount && canPossiblyHalt;
        }
        else if (nullptr != this->statementMap && this->statementMap->isSubexpression && STEP_IN != stepType)
        {
            // Only step into started from subexpression is allowed to stop on another subexpression
            Js::FunctionBody* pCurrentFuncBody = haltState->GetFunction();
            Js::FunctionBody::StatementMap* map = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(byteOffset, false);
            if (nullptr != map && map->isSubexpression)    // Execute remaining Subexpressions
            {
                fCanHalt = false;
            }
            else
            {
                Js::FunctionBody::StatementMap* outerMap = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(this->statementMap->byteCodeSpan.begin, true);
                if (nullptr != outerMap && map == outerMap) // Execute the rest of current regular statement
                {
                    fCanHalt = false;
                }
                else
                {
                    fCanHalt = canPossiblyHalt;
                }
            }
        }
        else
        {
            // Match if we are no longer on the original statement.  Stepping means move off current statement.
            if (body != this->body || NULL == this->statementMap ||
                !this->statementMap->byteCodeSpan.Includes(byteOffset))
            {
                fCanHalt = canPossiblyHalt;
            }
        }
        // At this point we are verifying of global return opcode.
        // The global returns are alway added as a zero range begin with zero.

        if (fCanHalt && originalOpcode == OpCode::Ret)
        {
            Js::FunctionBody* pCurrentFuncBody = haltState->GetFunction();
            Js::FunctionBody::StatementMap* map = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(byteOffset, true);

            fCanHalt = !FunctionBody::IsDummyGlobalRetStatement(&map->sourceSpan);
            if (fCanHalt)
            {
                // We are breaking at last line of function, imagine '}'
                AddReturnToReturnedValueContainer();
            }
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(stepType = %d) returning %d "), stepType, fCanHalt);
        return fCanHalt;
    }
    //
    // Loads the profile from the WININET cache
    //
    bool SourceDynamicProfileManager::LoadFromProfileCache(IActiveScriptDataCache* profileDataCache, LPCWSTR url)
    {
    #ifdef ENABLE_WININET_PROFILE_DATA_CACHE
        AssertMsg(CONFIG_FLAG(WininetProfileCache), "Profile caching should be enabled for us to get here");
        Assert(profileDataCache);
        AssertMsg(!IsProfileLoadedFromWinInet(), "Duplicate profile cache loading?");

        // Keep a copy of this and addref it
        profileDataCache->AddRef();
        this->profileDataCache = profileDataCache;

        IStream* readStream;
        HRESULT hr = profileDataCache->GetReadDataStream(&readStream);
        if(SUCCEEDED(hr))
        {
            Assert(readStream != nullptr);
            // stream reader owns the stream and will close it on destruction
            SimpleStreamReader streamReader(readStream);
            DWORD jscriptMajorVersion;
            DWORD jscriptMinorVersion;
            if(FAILED(AutoSystemInfo::GetJscriptFileVersion(&jscriptMajorVersion, &jscriptMinorVersion)))
            {
                return false;
            }

            DWORD majorVersion;
            if(!streamReader.Read(&majorVersion) || majorVersion != jscriptMajorVersion)
            {
                return false;
            }

            DWORD minorVersion;
            if(!streamReader.Read(&minorVersion) || minorVersion != jscriptMinorVersion)
            {
                return false;
            }

            uint numberOfFunctions;
            if(!streamReader.Read(&numberOfFunctions) || numberOfFunctions > MAX_FUNCTION_COUNT)
            {
                return false;
            }
            BVFixed* functions = BVFixed::New(numberOfFunctions, this->recycler);
            if(!streamReader.ReadArray(functions->GetData(), functions->WordCount()))
            {
                return false;
            }
            this->cachedStartupFunctions = functions;
            OUTPUT_TRACE(Js::DynamicProfilePhase, L"Profile load succeeded. Function count: %d  %s\n", numberOfFunctions, url);
#if DBG_DUMP
            if(PHASE_TRACE1(Js::DynamicProfilePhase) && Js::Configuration::Global.flags.Verbose)
            {
                OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Profile loaded:\n");
                functions->Dump();
            }
#endif
            return true;
        }
        else if (hr == HRESULT_FROM_WIN32(ERROR_WRITE_PROTECT))
        {
            this->isNonCachableScript = true;
            OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Profile load failed. Non-cacheable resource. %s\n", url);
        }
        else
        {
            OUTPUT_TRACE(Js::DynamicProfilePhase, L"Profile load failed. No read stream. %s\n", url);
        }
#endif
        return false;
    }
Ejemplo n.º 21
0
    bool ProbeContainer::DispatchExceptionBreakpoint(InterpreterHaltState* pHaltState)
    {
        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchExceptionBreakpoint: start: this=%p, pHaltState=%p\n"), this, pHaltState);
        bool fSuccess = false;
        if (!haltCallbackProbe || haltCallbackProbe->IsInClosedState() || debugManager->IsAtDispatchHalt())
        {
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchExceptionBreakpoint: not in break mode: pHaltState=%p\n"), pHaltState);
            // Will not be able to handle multiple break-hits.
            return fSuccess;
        }

        Assert(pHaltState->stopType == STOP_EXCEPTIONTHROW);

        jsExceptionObject = pHaltState->exceptionObject->GetThrownObject(nullptr);

        // Will store current offset of the bytecode block.
        int currentOffset = -1;

        __try
        {
            InitializeLocation(pHaltState, false);
            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchExceptionBreakpoint: initialized location: pHaltState=%p, IsInterpreterFrame=%d\n"),
                pHaltState, pHaltState->IsValid(), pHaltState->topFrame && pHaltState->topFrame->IsInterpreterFrame());

            // The ByteCodeReader should be available at this point, but because of possibility of garbled frame, we shouldn't hit AV
            if (pHaltState->IsValid() && pHaltState->GetFunction()->GetScriptContext()->IsScriptContextInDebugMode())
            {
#if DBG
                pHaltState->GetFunction()->MustBeInDebugMode();
#endif

                // For interpreter frames, change the current location pointer of bytecode block, as it might be pointing to the next statement on the body.
                // In order to generated proper binding of break on exception to the statement, the bytecode offset needed to be on the same span
                // of the statement.
                // For native frames the offset is always current.
                // Move back a single byte to ensure that it falls under on the same statement.
                if (pHaltState->topFrame->IsInterpreterFrame())
                {
                    currentOffset = pHaltState->GetCurrentOffset();
                    Assert(currentOffset > 0);
                    pHaltState->SetCurrentOffset(currentOffset - 1);
                }

                // an inline breakpoint is being dispatched deactivate other stopping controllers
                debugManager->stepController.Deactivate(pHaltState);
                debugManager->asyncBreakController.Deactivate();

                pHaltState->GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);

                ScriptContext *pTopFuncContext = pHaltState->GetFunction()->GetScriptContext();

                // If the top function's context is different from the current context, that means current frame is not alive anymore and breaking here cannot not happen.
                // So in that case we will consider the top function's context and break on that context.
                if (pTopFuncContext != pScriptContext)
                {
                    OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchExceptionBreakpoint: top function's context is different from the current context: pHaltState=%p, haltCallbackProbe=%p\n"),
                        pHaltState, pTopFuncContext->GetDebugContext()->GetProbeContainer()->haltCallbackProbe);
                    if (pTopFuncContext->GetDebugContext()->GetProbeContainer()->haltCallbackProbe)
                    {
                        pTopFuncContext->GetDebugContext()->GetProbeContainer()->haltCallbackProbe->DispatchHalt(pHaltState);
                        fSuccess = true;
                    }
                }
                else
                {
                    haltCallbackProbe->DispatchHalt(pHaltState);
                    fSuccess = true;
                }
            }
        }
        __finally
        {
            // If the next statement has changed, we need to log that to exception object so that it will not try to advance to next statement again.
            pHaltState->exceptionObject->SetIgnoreAdvanceToNextStatement(IsNextStatementChanged);

            // Restore the current offset;
            if (currentOffset != -1 && pHaltState->topFrame->IsInterpreterFrame())
            {
                pHaltState->SetCurrentOffset(currentOffset);
            }

            DestroyLocation();
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchExceptionBreakpoint: end: pHaltState=%p, fSuccess=%d\n"), pHaltState, fSuccess);
        return fSuccess;
    }