JSBool
xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text)
{
    if (!cx || !text) {
        DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n");
        return false;
    }

    DebugDump("js[%d]> %s\n", frameno, text);

    uint32_t num = 0;

    JSAbstractFramePtr frame = JSNullFramePtr();

    JSBrokenFrameIterator iter(cx);
    while (!iter.done()) {
        if (num == frameno) {
            frame = iter.abstractFramePtr();
            break;
        }
        ++iter;
        num++;
    }

    if (!frame) {
        DebugDump("%s", "invalid frame number!\n");
        return false;
    }

    JSAutoRequest ar(cx);

    JSExceptionState* exceptionState = JS_SaveExceptionState(cx);
    JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);

    jsval rval;
    JSString* str;
    JSAutoByteString bytes;
    if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) &&
        nullptr != (str = JS_ValueToString(cx, rval)) &&
        bytes.encode(cx, str)) {
        DebugDump("%s\n", bytes.ptr());
    } else
        DebugDump("%s", "eval failed!\n");
    JS_SetErrorReporter(cx, older);
    JS_RestoreExceptionState(cx, exceptionState);
    return true;
}
Example #2
0
static void
_interpreterTrace(JSDContext* jsdc, JSContext *cx, JSAbstractFramePtr frame,
                  bool isConstructing, JSBool before)
{
    JSDScript* jsdscript = NULL;
    JSScript * script;
    static indent = 0;
    JSString* funName = NULL;

    script = frame.script();
    if(script)
    {
        JSD_LOCK_SCRIPTS(jsdc);
        jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
        JSD_UNLOCK_SCRIPTS(jsdc);
        if(jsdscript)
            funName = JSD_GetScriptFunctionId(jsdc, jsdscript);
    }

    if(before)
        printf("%sentering ", _indentSpaces(indent++));
    else
        printf("%sleaving ", _indentSpaces(--indent));

    if (!funName)
        printf("TOP_LEVEL");
    else
        JS_FileEscapedString(stdout, funName, 0);

    if(before)
    {
        jsval thisVal;

        printf("%s this: ", isConstructing ? "constructing":"");

        if (JS_GetFrameThis(cx, frame, &thisVal))
            printf("0x%0llx", (uintptr_t) thisVal);
        else
            puts("<unavailable>");
    }
    printf("\n");
    JS_ASSERT(indent >= 0);
}
Example #3
0
void
jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj,
                 JSAbstractFramePtr frame)
{
    JSDObject* jsdobj;
    JS::RootedScript script(cx);
    JSDScript* jsdscript;
    const char* ctorURL;
    JSString* ctorNameStr;
    const char* ctorName;

    JSD_LOCK_OBJECTS(jsdc);
    jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj);
    if( jsdobj && !jsdobj->ctorURL )
    {
        script = frame.script();
        if( script )
        {
            ctorURL = JS_GetScriptFilename(cx, script);
            if( ctorURL )
                jsdobj->ctorURL = jsd_AddAtom(jsdc, ctorURL);

            JSD_LOCK_SCRIPTS(jsdc);
            jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
            JSD_UNLOCK_SCRIPTS(jsdc);
            if( jsdscript && (ctorNameStr = jsd_GetScriptFunctionId(jsdc, jsdscript)) ) {
                if( (ctorName = JS_EncodeString(cx, ctorNameStr)) ) {
                    jsdobj->ctorName = jsd_AddAtom(jsdc, ctorName);
                    JS_free(cx, (void *) ctorName);
                }
            }
            jsdobj->ctorLineno = JS_GetScriptBaseLineNumber(cx, script);
        }
    }
    TRACEOBJ(jsdc, jsdobj, 3);
    JSD_UNLOCK_OBJECTS(jsdc);
}
Example #4
0
JSDThreadState*
jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
{
    JSDThreadState* jsdthreadstate;

    jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
    if( ! jsdthreadstate )
        return nullptr;

    jsdthreadstate->context = cx;
    jsdthreadstate->thread = JSD_CURRENT_THREAD();
    JS_INIT_CLIST(&jsdthreadstate->stack);
    jsdthreadstate->stackDepth = 0;

    JS_BeginRequest(jsdthreadstate->context);

    JSBrokenFrameIterator iter(cx);
    while(!iter.done())
    {
        JSAbstractFramePtr frame = iter.abstractFramePtr();
        JS::RootedScript script(cx, frame.script());
        uintptr_t  pc = (uintptr_t)frame.pc();
        JS::RootedValue dummyThis(cx);

        /*
         * don't construct a JSDStackFrame for dummy frames (those without a
         * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
         * isn't set.
         */
        if (frame.getThisValue(cx, &dummyThis))
        {
            bool isConstructing = iter.isConstructing();
            JSDStackFrameInfo *frameInfo = _addNewFrame( jsdc, jsdthreadstate, script, pc, isConstructing, frame );

            if ((jsdthreadstate->stackDepth == 0 && !frameInfo) ||
                (jsdthreadstate->stackDepth == 1 && frameInfo &&
                 frameInfo->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frameInfo->jsdscript)))
            {
                /*
                 * if we failed to create the first frame, or the top frame
                 * is not enabled for debugging, fail the entire thread state.
                 */
                JS_INIT_CLIST(&jsdthreadstate->links);
                JS_EndRequest(jsdthreadstate->context);
                jsd_DestroyThreadState(jsdc, jsdthreadstate);
                return nullptr;
            }
        }

        ++iter;
    }
    JS_EndRequest(jsdthreadstate->context);

    if (jsdthreadstate->stackDepth == 0)
    {
        free(jsdthreadstate);
        return nullptr;
    }
    
    JSD_LOCK_THREADSTATES(jsdc);
    JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdthreadstate;
}
Example #5
0
JSBool
_callHook(JSDContext *jsdc, JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
          JSBool before, unsigned type, JSD_CallHookProc hook, void *hookData)
{
    JSDScript*        jsdscript;
    JSScript*         jsscript;
    JSBool            hookresult = JS_TRUE;
    
    if (!jsdc || !jsdc->inited)
        return JS_FALSE;

    if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
    {
        /* no hook to call, no profile data needs to be collected,
         * so there is nothing to do here.
         */
        return hookresult;
    }

    if (before && isConstructing) {
        js::RootedValue newObj(cx);
        if (!frame.getThisValue(cx, &newObj))
            return JS_FALSE;
        jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), frame);
    }

    jsscript = frame.script();
    if (jsscript)
    {
        JSD_LOCK_SCRIPTS(jsdc);
        jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, frame);
        JSD_UNLOCK_SCRIPTS(jsdc);
    
        if (jsdscript)
        {
            if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript))
            {
                JSDProfileData *pdata;
                pdata = jsd_GetScriptProfileData (jsdc, jsdscript);
                if (pdata)
                {
                    if (before)
                    {
                        if (!pdata->lastCallStart)
                        {
                            int64_t now;
                            JSDProfileData *callerpdata;
                            
                            /* Get the time just the once, for consistency. */
                            now = JS_Now();
                            /* This contains a pointer to the profile data for
                             * the caller of this function. */
                            callerpdata = jsdc->callingFunctionPData;
                            if (callerpdata)
                            {
                                int64_t ll_delta;
                                pdata->caller = callerpdata;
                                /* We need to 'stop' the timer for the caller.
                                 * Use time since last return if appropriate. */
                                ll_delta = jsdc->lastReturnTime
                                           ? now - jsdc->lastReturnTime
                                           : now - callerpdata->lastCallStart;
                                callerpdata->runningTime += ll_delta;
                            }
                            /* We're the new current function, and no return
                             * has happened yet. */
                            jsdc->callingFunctionPData = pdata;
                            jsdc->lastReturnTime = 0;
                            /* This function has no running time (just been
                             * called!), and we'll need the call start time. */
                            pdata->runningTime = 0;
                            pdata->lastCallStart = now;
                        } else {
                            if (++pdata->recurseDepth > pdata->maxRecurseDepth)
                                pdata->maxRecurseDepth = pdata->recurseDepth;
                        }
                        /* make sure we're called for the return too. */
                        hookresult = JS_TRUE;
                    } else if (!pdata->recurseDepth && pdata->lastCallStart) {
                        int64_t now, ll_delta;
                        double delta;
                        now = JS_Now();
                        ll_delta = now - pdata->lastCallStart;
                        delta = ll_delta;
                        delta /= 1000.0;
                        pdata->totalExecutionTime += delta;
                        /* minExecutionTime starts as 0, so we need to overwrite
                         * it on the first call always. */
                        if ((0 == pdata->callCount) ||
                            delta < pdata->minExecutionTime)
                        {
                            pdata->minExecutionTime = delta;
                        }
                        if (delta > pdata->maxExecutionTime)
                            pdata->maxExecutionTime = delta;
                        
                        /* If we last returned from a function (as opposed to
                         * having last entered this function), we need to inc.
                         * the running total by the time delta since the last
                         * return, and use the running total instead of the
                         * delta calculated above. */
                        if (jsdc->lastReturnTime)
                        {
                            /* Add last chunk to running time, and use total
                             * running time as 'delta'. */
                            ll_delta = now - jsdc->lastReturnTime;
                            pdata->runningTime += ll_delta;
                            delta = pdata->runningTime;
                            delta /= 1000.0;
                        }
                        
                        pdata->totalOwnExecutionTime += delta;
                        /* See minExecutionTime comment above. */
                        if ((0 == pdata->callCount) ||
                            delta < pdata->minOwnExecutionTime)
                        {
                            pdata->minOwnExecutionTime = delta;
                        }
                        if (delta > pdata->maxOwnExecutionTime)
                            pdata->maxOwnExecutionTime = delta;
                        
                        /* Current function is now our caller. */
                        jsdc->callingFunctionPData = pdata->caller;
                        /* No hanging pointers, please. */
                        pdata->caller = NULL;
                        /* Mark the time we returned, and indicate this
                         * function is no longer running. */
                        jsdc->lastReturnTime = now;
                        pdata->lastCallStart = 0;
                        ++pdata->callCount;
                    } else if (pdata->recurseDepth) {
                        --pdata->recurseDepth;
                        ++pdata->callCount;
                    }
                }
                if (hook)
                    jsd_CallCallHook (jsdc, cx, type, hook, hookData);
            } else {
                if (hook)
                    hookresult = 
                        jsd_CallCallHook (jsdc, cx, type, hook, hookData);
                else
                    hookresult = JS_TRUE;
            }
        }
    }

#ifdef JSD_TRACE
    _interpreterTrace(jsdc, cx, frame, isConstructing, before);
    return JS_TRUE;
#else
    return hookresult;
#endif

}