Bug 605330 - extend jscalls (bug 507012) tracking to cover JM and fix some mismatched calls, r=dvander, a=NPODB

--HG--
extra : rebase_source : 77f64a8ee2c88cbb00ac5671ba2532f71551f28b
This commit is contained in:
Steve Fink 2010-09-20 12:43:51 -07:00
parent c27fce5107
commit 7cdb5fabc2
10 changed files with 109 additions and 87 deletions

View File

@ -16,9 +16,9 @@ static void
funcTransition(const JSFunction *, funcTransition(const JSFunction *,
const JSScript *, const JSScript *,
const JSContext *cx, const JSContext *cx,
JSBool entering) int entering)
{ {
if (entering) { if (entering > 0) {
++depth; ++depth;
++enters; ++enters;
if (! JS_ON_TRACE(cx)) if (! JS_ON_TRACE(cx))
@ -32,7 +32,7 @@ funcTransition(const JSFunction *,
static JSBool called2 = false; static JSBool called2 = false;
static void static void
funcTransition2(const JSFunction *, const JSScript*, const JSContext*, JSBool) funcTransition2(const JSFunction *, const JSScript*, const JSContext*, int)
{ {
called2 = true; called2 = true;
} }
@ -43,7 +43,7 @@ static void
funcTransitionOverlay(const JSFunction *fun, funcTransitionOverlay(const JSFunction *fun,
const JSScript *script, const JSScript *script,
const JSContext *cx, const JSContext *cx,
JSBool entering) int entering)
{ {
(*innerCallback)(fun, script, cx, entering); (*innerCallback)(fun, script, cx, entering);
overlays++; overlays++;
@ -66,7 +66,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
// Check whether the basic function tracking works // Check whether the basic function tracking works
EXEC("f(1)"); EXEC("f(1)");
CHECK(enters == 2 && leaves == 2 && depth == 0); CHECK(enters == 1+1 && leaves == 1+1 && depth == 0);
// Can we switch to a different callback? // Can we switch to a different callback?
enters = 777; enters = 777;
@ -91,7 +91,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
EXEC("function g () { ++x; }"); EXEC("function g () { ++x; }");
interpreted = enters = leaves = depth = 0; interpreted = enters = leaves = depth = 0;
EXEC("for (i = 0; i < 50; ++i) { g(); }"); EXEC("for (i = 0; i < 50; ++i) { g(); }");
CHECK(enters == 50+1 && leaves == 50+1 && depth == 0); CHECK(enters == 1+50 && leaves == 1+50 && depth == 0);
// If this fails, it means that the code was interpreted rather // If this fails, it means that the code was interpreted rather
// than trace-JITted, and so is not testing what it's supposed to // than trace-JITted, and so is not testing what it's supposed to
@ -114,7 +114,7 @@ BEGIN_TEST(testFuncCallback_bug507012)
CHECK(enters == 1); CHECK(enters == 1);
CHECK(leaves == 1); CHECK(leaves == 1);
CHECK(depth == 0); CHECK(depth == 0);
CHECK(overlays == 2); // 1 each for enter and exit CHECK(overlays == enters + leaves);
interpreted = enters = leaves = depth = overlays = 0; interpreted = enters = leaves = depth = overlays = 0;
#endif #endif

View File

@ -3307,8 +3307,17 @@ JS_ClearContextThread(JSContext *cx);
typedef void (*JSFunctionCallback)(const JSFunction *fun, typedef void (*JSFunctionCallback)(const JSFunction *fun,
const JSScript *scr, const JSScript *scr,
const JSContext *cx, const JSContext *cx,
JSBool entering); int entering);
/*
* The callback is expected to be quick and noninvasive. It should not
* trigger interrupts, turn on debugging, or produce uncaught JS
* exceptions. The state of the stack and registers in the context
* cannot be relied upon, since this callback may be invoked directly
* from either JIT. The 'entering' field means we are entering a
* function if it is positive, leaving a function if it is zero or
* negative.
*/
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb); JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb);

View File

@ -2176,7 +2176,7 @@ struct JSContext
void doFunctionCallback(const JSFunction *fun, void doFunctionCallback(const JSFunction *fun,
const JSScript *scr, const JSScript *scr,
JSBool entering) const int entering) const
{ {
if (functionCallback) if (functionCallback)
functionCallback(fun, scr, this, entering); functionCallback(fun, scr, this, entering);

View File

@ -1347,10 +1347,10 @@ DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp)
JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun); JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun);
JS_ASSERT(IsBuiltinEvalFunction(evalfun)); JS_ASSERT(IsBuiltinEvalFunction(evalfun));
AutoFunctionCallProbe callProbe(cx, evalfun);
JSStackFrame *caller = cx->fp(); JSStackFrame *caller = cx->fp();
JS_ASSERT(caller->isScriptFrame()); JS_ASSERT(caller->isScriptFrame());
AutoFunctionCallProbe callProbe(cx, evalfun, caller->script());
JSObject *scopeChain = JSObject *scopeChain =
GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH); GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);
if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain)) if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain))
@ -2214,7 +2214,8 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame()) if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame())
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData)); fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
Probes::enterJSFun(cx, fp->maybeFun()); if (!fp->isExecuteFrame())
Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript());
return true; return true;
} }
@ -4751,9 +4752,9 @@ BEGIN_CASE(JSOP_FUNCALL)
DO_OP(); DO_OP();
} }
Probes::enterJSFun(cx, newfun); Probes::enterJSFun(cx, newfun, script);
JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp); JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp);
Probes::exitJSFun(cx, newfun); Probes::exitJSFun(cx, newfun, script);
regs.sp = vp + 1; regs.sp = vp + 1;
if (!ok) if (!ok)
goto error; goto error;

View File

@ -592,7 +592,7 @@ InvokeSessionGuard::invoke(JSContext *cx) const
JSBool ok; JSBool ok;
{ {
AutoPreserveEnumerators preserve(cx); AutoPreserveEnumerators preserve(cx);
Probes::enterJSFun(cx, fp->fun()); Probes::enterJSFun(cx, fp->fun(), script_);
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
AutoInterpPreparer prepareInterp(cx, script_); AutoInterpPreparer prepareInterp(cx, script_);
ok = mjit::EnterMethodJIT(cx, fp, code_, stackLimit_); ok = mjit::EnterMethodJIT(cx, fp, code_, stackLimit_);
@ -601,7 +601,7 @@ InvokeSessionGuard::invoke(JSContext *cx) const
cx->regs->pc = script_->code; cx->regs->pc = script_->code;
ok = Interpret(cx, cx->fp()); ok = Interpret(cx, cx->fp());
#endif #endif
Probes::exitJSFun(cx, fp->fun()); Probes::exitJSFun(cx, fp->fun(), script_);
} }
PutActivationObjects(cx, fp); PutActivationObjects(cx, fp);
@ -706,7 +706,9 @@ ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
static inline bool static inline bool
ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok) ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
{ {
Probes::exitJSFun(cx, fp->maybeFun()); if (!fp->isExecuteFrame())
Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
JSInterpreterHook hook = cx->debugHooks->callHook; JSInterpreterHook hook = cx->debugHooks->callHook;
if (hook && fp->hasHookData() && !fp->isExecuteFrame()) if (hook && fp->hasHookData() && !fp->isExecuteFrame())
hook(cx, fp, JS_FALSE, &ok, fp->hookData()); hook(cx, fp, JS_FALSE, &ok, fp->hookData());

View File

@ -152,16 +152,16 @@ Probes::FunctionName(JSContext *cx, const JSFunction *fun)
* a number of usually unused lines of code would cause. * a number of usually unused lines of code would cause.
*/ */
void void
Probes::enterJSFunImpl(JSContext *cx, const JSFunction *fun) Probes::enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script)
{ {
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(FUN_SCRIPT(fun)), FunctionClassname(fun), JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun)); FunctionName(cx, fun));
} }
void void
Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun) Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script)
{ {
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(FUN_SCRIPT(fun)), FunctionClassname(fun), JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun)); FunctionName(cx, fun));
} }

View File

@ -52,16 +52,14 @@ class Probes {
static int FunctionLineNumber(JSContext *cx, const JSFunction *fun); static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
static const char *FunctionName(JSContext *cx, const JSFunction *fun); static const char *FunctionName(JSContext *cx, const JSFunction *fun);
static void enterJSFunImpl(JSContext *cx, const JSFunction *fun); static void enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script);
static void handleFunctionReturn(JSContext *cx, JSFunction *fun); static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
static void finalizeObjectImpl(JSObject *obj); static void finalizeObjectImpl(JSObject *obj);
public: public:
/* static bool callTrackingActive(JSContext *);
* If |lval| is provided to the enter/exit methods, it is tested to see if
* it is a function as a predicate to the dtrace event emission. static void enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
*/ static void exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
static void enterJSFun(JSContext *cx, JSFunction *fun, js::Value *lval = NULL);
static void exitJSFun(JSContext *cx, JSFunction *fun, js::Value *lval = NULL);
static void startExecution(JSContext *cx, JSScript *script); static void startExecution(JSContext *cx, JSScript *script);
static void stopExecution(JSContext *cx, JSScript *script); static void stopExecution(JSContext *cx, JSScript *script);
@ -113,31 +111,47 @@ class Probes {
static JSBool CustomMark(int marker); static JSBool CustomMark(int marker);
}; };
inline void inline bool
Probes::enterJSFun(JSContext *cx, JSFunction *fun, js::Value *lval) Probes::callTrackingActive(JSContext *cx)
{ {
#ifdef INCLUDE_MOZILLA_DTRACE #ifdef INCLUDE_MOZILLA_DTRACE
if (!lval || IsFunctionObject(*lval)) { if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED()) return true;
enterJSFunImpl(cx, fun);
}
#endif #endif
#ifdef MOZ_TRACE_JSCALLS #ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, fun ? FUN_SCRIPT(fun) : NULL, true); if (cx->functionCallback)
return true;
#endif
#ifdef MOZ_ETW
if (ProfilingActive && MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry))
return true;
#endif
return false;
}
inline void
Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
{
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
enterJSFunImpl(cx, fun, script);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, script, counter);
#endif #endif
} }
inline void inline void
Probes::exitJSFun(JSContext *cx, JSFunction *fun, js::Value *lval) Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
{ {
#ifdef INCLUDE_MOZILLA_DTRACE #ifdef INCLUDE_MOZILLA_DTRACE
if (!lval || IsFunctionObject(*lval)) { if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
if (JAVASCRIPT_FUNCTION_RETURN_ENABLED()) handleFunctionReturn(cx, fun, script);
handleFunctionReturn(cx, fun);
}
#endif #endif
#ifdef MOZ_TRACE_JSCALLS #ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, fun ? FUN_SCRIPT(fun) : NULL, false); if (counter > 0)
counter = -counter;
cx->doFunctionCallback(fun, script, counter);
#endif #endif
} }
@ -170,11 +184,11 @@ Probes::startExecution(JSContext *cx, JSScript *script)
{ {
#ifdef INCLUDE_MOZILLA_DTRACE #ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_EXECUTE_START_ENABLED()) if (JAVASCRIPT_EXECUTE_START_ENABLED())
JAVASCRIPT_EXECUTE_START(script->filename ? (char *)script->filename : nullName, JAVASCRIPT_EXECUTE_START((script->filename ? (char *)script->filename : nullName),
script->lineno); script->lineno);
#endif #endif
#ifdef MOZ_TRACE_JSCALLS #ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(NULL, script, true); cx->doFunctionCallback(NULL, script, 1);
#endif #endif
} }
@ -183,11 +197,11 @@ Probes::stopExecution(JSContext *cx, JSScript *script)
{ {
#ifdef INCLUDE_MOZILLA_DTRACE #ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_EXECUTE_DONE_ENABLED()) if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
JAVASCRIPT_EXECUTE_DONE(script->filename ? (char *)script->filename : nullName, JAVASCRIPT_EXECUTE_DONE((script->filename ? (char *)script->filename : nullName),
script->lineno); script->lineno);
#endif #endif
#ifdef MOZ_TRACE_JSCALLS #ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(NULL, script, false); cx->doFunctionCallback(NULL, script, 0);
#endif #endif
} }
@ -219,19 +233,19 @@ inline JSBool Probes::CustomMark(int marker) { return JS_TRUE; }
struct AutoFunctionCallProbe { struct AutoFunctionCallProbe {
JSContext * const cx; JSContext * const cx;
JSFunction *fun; JSFunction *fun;
js::Value *lval; JSScript *script;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER JS_DECL_USE_GUARD_OBJECT_NOTIFIER
AutoFunctionCallProbe(JSContext *cx, JSFunction *fun, js::Value *lval = NULL AutoFunctionCallProbe(JSContext *cx, JSFunction *fun, JSScript *script
JS_GUARD_OBJECT_NOTIFIER_PARAM) JS_GUARD_OBJECT_NOTIFIER_PARAM)
: cx(cx), fun(fun), lval(lval) : cx(cx), fun(fun), script(script)
{ {
JS_GUARD_OBJECT_NOTIFIER_INIT; JS_GUARD_OBJECT_NOTIFIER_INIT;
Probes::enterJSFun(cx, fun, lval); Probes::enterJSFun(cx, fun, script);
} }
~AutoFunctionCallProbe() { ~AutoFunctionCallProbe() {
Probes::exitJSFun(cx, fun, lval); Probes::exitJSFun(cx, fun, script);
} }
}; };

View File

@ -10236,22 +10236,20 @@ TraceRecorder::record_JSOP_LEAVEWITH()
return ARECORD_STOP; return ARECORD_STOP;
} }
#ifdef MOZ_TRACE_JSCALLS
// Usually, cx->doFunctionCallback() is invoked via DTrace::enterJSFun
// and friends, but the DTrace:: probes use fp and therefore would
// need to break out of tracing. So we define a functionProbe()
// callback to be called by generated code when a Javascript function
// is entered or exited.
static JSBool JS_FASTCALL static JSBool JS_FASTCALL
functionProbe(JSContext *cx, JSFunction *fun, JSBool enter) functionProbe(JSContext *cx, JSFunction *fun, int enter)
{ {
cx->doFunctionCallback(fun, FUN_SCRIPT(fun), enter); #ifdef MOZ_TRACE_JSCALLS
JSScript *script = fun ? FUN_SCRIPT(fun) : NULL;
if (enter > 0)
Probes::enterJSFun(cx, fun, script, enter);
else
Probes::exitJSFun(cx, fun, script, enter);
#endif
return true; return true;
} }
JS_DEFINE_CALLINFO_3(static, BOOL, functionProbe, CONTEXT, FUNCTION, BOOL, JS_DEFINE_CALLINFO_3(static, BOOL, functionProbe, CONTEXT, FUNCTION, INT32, 0, ACCSET_ALL)
0, ACCSET_STORE_ANY)
#endif
JS_REQUIRES_STACK AbortableRecordingStatus JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_RETURN() TraceRecorder::record_JSOP_RETURN()
@ -10264,13 +10262,11 @@ TraceRecorder::record_JSOP_RETURN()
putActivationObjects(); putActivationObjects();
#ifdef MOZ_TRACE_JSCALLS if (Probes::callTrackingActive(cx)) {
if (cx->functionCallback) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins };
LIns* call_ins = w.call(&functionProbe_ci, args); LIns* call_ins = w.call(&functionProbe_ci, args);
guard(false, w.eqi0(call_ins), MISMATCH_EXIT); guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
} }
#endif
/* If we inlined this function call, make the return value available to the caller code. */ /* If we inlined this function call, make the return value available to the caller code. */
Value& rval = stackval(-1); Value& rval = stackval(-1);
@ -11389,8 +11385,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
*/ */
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &fval.toObject()); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &fval.toObject());
#ifdef MOZ_TRACE_JSCALLS if (Probes::callTrackingActive(cx)) {
if (cx->functionCallback) {
JSScript *script = FUN_SCRIPT(fun); JSScript *script = FUN_SCRIPT(fun);
if (! script || ! script->isEmpty()) { if (! script || ! script->isEmpty()) {
LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins }; LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins };
@ -11398,7 +11393,6 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
guard(false, w.eqi0(call_ins), MISMATCH_EXIT); guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
} }
} }
#endif
if (FUN_INTERPRETED(fun)) if (FUN_INTERPRETED(fun))
return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW); return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW);
@ -11420,13 +11414,11 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
} }
RecordingStatus rs = callNative(argc, mode); RecordingStatus rs = callNative(argc, mode);
#ifdef MOZ_TRACE_JSCALLS if (Probes::callTrackingActive(cx)) {
if (cx->functionCallback) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(fun), cx_ins }; LIns* args[] = { w.immi(0), w.nameImmpNonGC(fun), cx_ins };
LIns* call_ins = w.call(&functionProbe_ci, args); LIns* call_ins = w.call(&functionProbe_ci, args);
guard(false, w.eqi0(call_ins), MISMATCH_EXIT); guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
} }
#endif
return rs; return rs;
} }
@ -15514,13 +15506,11 @@ TraceRecorder::record_JSOP_STOP()
putActivationObjects(); putActivationObjects();
#ifdef MOZ_TRACE_JSCALLS if (Probes::callTrackingActive(cx)) {
if (cx->functionCallback) {
LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins };
LIns* call_ins = w.call(&functionProbe_ci, args); LIns* call_ins = w.call(&functionProbe_ci, args);
guard(false, w.eqi0(call_ins), MISMATCH_EXIT); guard(false, w.eqi0(call_ins), MISMATCH_EXIT);
} }
#endif
/* /*
* We know falling off the end of a constructor returns the new object that * We know falling off the end of a constructor returns the new object that

View File

@ -361,7 +361,7 @@ mjit::Compiler::generatePrologue()
if (isConstructing) if (isConstructing)
constructThis(); constructThis();
if (debugMode) if (debugMode || Probes::callTrackingActive(cx))
stubCall(stubs::EnterScript); stubCall(stubs::EnterScript);
return Compile_Okay; return Compile_Okay;
@ -2199,7 +2199,7 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
/* Only the top of the stack can be returned. */ /* Only the top of the stack can be returned. */
JS_ASSERT_IF(fe, fe == frame.peek(-1)); JS_ASSERT_IF(fe, fe == frame.peek(-1));
if (debugMode) { if (debugMode || Probes::callTrackingActive(cx)) {
prepareStubCall(Uses(0)); prepareStubCall(Uses(0));
stubCall(stubs::LeaveScript); stubCall(stubs::LeaveScript);
} }

View File

@ -608,12 +608,15 @@ stubs::EnterScript(VMFrame &f)
{ {
JSStackFrame *fp = f.fp(); JSStackFrame *fp = f.fp();
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSInterpreterHook hook = cx->debugHooks->callHook;
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame()) { if (fp->script()->debugMode) {
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData)); JSInterpreterHook hook = cx->debugHooks->callHook;
if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame()) {
fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
}
} }
Probes::enterJSFun(cx, fp->maybeFun()); Probes::enterJSFun(cx, fp->maybeFun(), fp->script());
} }
void JS_FASTCALL void JS_FASTCALL
@ -621,14 +624,17 @@ stubs::LeaveScript(VMFrame &f)
{ {
JSStackFrame *fp = f.fp(); JSStackFrame *fp = f.fp();
JSContext *cx = f.cx; JSContext *cx = f.cx;
Probes::exitJSFun(cx, fp->maybeFun()); Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
JSInterpreterHook hook = cx->debugHooks->callHook;
if (hook && fp->hasHookData() && !fp->isExecuteFrame()) { if (fp->script()->debugMode) {
JSBool ok = JS_TRUE; JSInterpreterHook hook = cx->debugHooks->callHook;
hook(cx, fp, JS_FALSE, &ok, fp->hookData());
if (!ok) if (hook && fp->hasHookData() && !fp->isExecuteFrame()) {
THROW(); JSBool ok = JS_TRUE;
hook(cx, fp, JS_FALSE, &ok, fp->hookData());
if (!ok)
THROW();
}
} }
} }