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); }
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); }
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; }
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 }