diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 7cc4447701a2..67f627ca7493 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4189,7 +4189,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) assertSameCompartment(cx, parent); // XXX no funobj for now if (!parent) { if (cx->hasfp()) - parent = GetScopeChain(cx, cx->fp()); + parent = GetScopeChain(cx, cx->fp(), ORIGIN_CLONE_FUNOBJ); if (!parent) parent = cx->globalObject; JS_ASSERT(parent); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index dc8dc803eda9..08f8487b0dba 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1395,7 +1395,7 @@ JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp) /* Force creation of argument and call objects if not yet created */ (void) JS_GetFrameCallObject(cx, fp); - return GetScopeChain(cx, fp); + return GetScopeChain(cx, fp, ORIGIN_GET_FRAME_SCOPE_CHAIN); } JS_PUBLIC_API(JSObject *) @@ -1417,7 +1417,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) * XXX ill-defined: null return here means error was reported, unlike a * null returned above or in the #else */ - return js_GetCallObject(cx, fp); + return js_GetCallObject(cx, fp, ORIGIN_GET_FRAME_OBJ); } JS_PUBLIC_API(JSBool) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 3c77e8c7f4b5..069c83d80693 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -359,7 +359,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun) * _DBG* opcodes used by wrappers created here must cope with unresolved * upvars and throw them as reference errors. Caveat debuggers! */ - JSObject *scopeChain = GetScopeChain(cx, fp); + JSObject *scopeChain = GetScopeChain(cx, fp, ORIGIN_WESC); if (!scopeChain) return NULL; @@ -948,7 +948,8 @@ namespace js { * on behalf of which the call object is being created. */ JSObject * -NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject *callee) +NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject *callee, + Origins origin) { size_t argsVars = bindings->countArgsAndVars(); size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars; @@ -977,6 +978,7 @@ NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject #endif callobj->setCallObjCallee(callee); + callobj->setOrigin(origin); return callobj; } @@ -995,17 +997,13 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp) } JSObject * -js_GetCallObject(JSContext *cx, JSStackFrame *fp) +js_GetCallObject(JSContext *cx, JSStackFrame *fp, Origins origin) { /* Create a call object for fp only if it lacks one. */ JS_ASSERT(fp->isFunctionFrame()); if (fp->hasCallObj()) return &fp->callObj(); - JS_ASSERT(!fp->isEvalFrame()); - if (fp->isEvalFrame()) - *((int *)0xeca1) = 0; - #ifdef DEBUG /* A call object should be a frame's outermost scope chain element. */ Class *clasp = fp->scopeChain().getClass(); @@ -1040,7 +1038,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp) } JSObject *callobj = - NewCallObject(cx, &fp->fun()->script()->bindings, fp->scopeChain(), &fp->callee()); + NewCallObject(cx, &fp->fun()->script()->bindings, fp->scopeChain(), &fp->callee(), origin); if (!callobj) return NULL; @@ -1061,7 +1059,7 @@ js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSO JS_ASSERT(!js_IsNamedLambda(fun)); JS_ASSERT(scopeChain); JS_ASSERT(callee); - return NewCallObject(cx, &fun->script()->bindings, *scopeChain, callee); + return NewCallObject(cx, &fun->script()->bindings, *scopeChain, callee, ORIGIN_ON_TRACE); } JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT, @@ -1373,24 +1371,67 @@ call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, return true; } -JS_PUBLIC_DATA(volatile JSStackFrame *volatile) leakage; +struct Cargo +{ + uint32 bef; + + JSObject *callObjCallee; + uint32 atomLength; + jschar atom[64]; + uint32 filenameLength; + char filename[128]; + uint32 lineno; + uint32 callObjFlags; + + uint32 aft; + + Cargo() : bef(0xaaaaaaaa), aft(0xbbbbbbbb) {} +}; + +JS_PUBLIC_DATA(Cargo *) cargoEscape; static void call_trace(JSTracer *trc, JSObject *obj) { - JSStackFrame frameCopy[3]; - JS_ASSERT(obj->isCall()); - if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) { - memset(&frameCopy[0], 0xaa, sizeof(JSStackFrame)); - memcpy(&frameCopy[1], fp, sizeof(JSStackFrame)); - memset(&frameCopy[2], 0xbb, sizeof(JSStackFrame)); - leakage = frameCopy; - bool bad = fp->isEvalFrame() && !fp->script()->strictModeCode; + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) { + + // TEMPORARY BUG FINDING CODE + Cargo cargo; + cargoEscape = &cargo; + + cargo.callObjFlags = obj->flags; + cargo.callObjCallee = obj->getCallObjCallee(); + + if (cargo.callObjCallee) { + JSFunction *fun = cargo.callObjCallee->getFunctionPrivate(); + if (fun->atom) { + cargo.atomLength = fun->atom->length(); + js_strncpy(cargo.atom, fun->atom->chars(), Min(cargo.atomLength, (uint32)64)); + } else { + strcpy((char *)cargo.atom, "(unnamed)"); + } + if (fun->isInterpreted()) { + JSScript *script = fun->script(); + cargo.lineno = script->lineno; + cargo.filenameLength = strlen(script->filename); + if (const char *filename = script->filename) { + strncpy(cargo.filename, filename, Min(cargo.filenameLength, (uint32)128)); + } else { + strcpy(cargo.filename, "(no file)"); + } + } else { + *((int *)0xbad1) = 0; + } + } else { + strcpy((char *)cargo.atom, "(eval)"); + } + + bool bad = obj != &fp->callObj(); JS_ASSERT(!bad); if (bad) - *(int *)0xbad = 0; + *((int *)0xbad2) = 0; /* * FIXME: Hide copies of stack values rooted by fp from the Cycle diff --git a/js/src/jsfun.h b/js/src/jsfun.h index a52092c9ed19..a9cafe7426ee 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -328,7 +328,8 @@ namespace js { * must be null. */ extern JSObject * -NewCallObject(JSContext *cx, js::Bindings *bindings, JSObject &scopeChain, JSObject *callee); +NewCallObject(JSContext *cx, js::Bindings *bindings, JSObject &scopeChain, JSObject *callee, + Origins origin); /* * NB: jsapi.h and jsobj.h must be included before any call to this macro. @@ -516,7 +517,7 @@ extern void js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, uintN flags); extern JSObject * -js_GetCallObject(JSContext *cx, JSStackFrame *fp); +js_GetCallObject(JSContext *cx, JSStackFrame *fp, Origins origin); extern JSObject * JS_FASTCALL js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 7208b005c5b4..aa9556370888 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -110,22 +110,6 @@ using namespace js::gc; JSObject *const JSStackFrame::sInvalidScopeChain = (JSObject *)0xbeef; #endif -JS_NEVER_INLINE void -js::PutActivationObjects(JSContext *cx, JSStackFrame *fp) -{ - JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame()); - - if (fp->isEvalFrame()) - *((int *)0x1337) = 0; - - /* The order is important as js_PutCallObject needs to access argsObj. */ - if (fp->hasCallObj()) { - js_PutCallObject(cx, fp); - } else if (fp->hasArgsObj()) { - js_PutArgsObject(cx, fp); - } -} - jsbytecode * JSStackFrame::pc(JSContext *cx, JSStackFrame *next) { @@ -265,7 +249,7 @@ js::GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen) * some other cases --- entering 'with' blocks, for example. */ static JSObject * -GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain) +GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain, Origins origin) { JSObject *sharedBlock = blockChain; @@ -293,7 +277,7 @@ GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain) if (fp->isFunctionFrame() && !fp->hasCallObj()) { JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); - if (!js_GetCallObject(cx, fp)) + if (!js_GetCallObject(cx, fp, origin)) return NULL; /* We know we must clone everything on blockChain. */ @@ -386,15 +370,15 @@ GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain) } JSObject * -js::GetScopeChain(JSContext *cx, JSStackFrame *fp) +js::GetScopeChain(JSContext *cx, JSStackFrame *fp, Origins origin) { - return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp)); + return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp), origin); } JSObject * -js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen) +js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen, Origins origin) { - return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen)); + return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen), origin); } /* Some objects (e.g., With) delegate 'this' to another object. */ @@ -709,7 +693,7 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags) cx->stack().pushInvokeFrame(cx, args, &frame); /* Now that the new frame is rooted, maybe create a call object. */ - if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp, ORIGIN_INVOKE)) return false; /* Run function until JSOP_STOP, JSOP_RETURN or error. */ @@ -949,7 +933,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script, */ if ((flags & JSFRAME_EVAL) && script->strictModeCode) { AutoScriptRooter root(cx, script); - initialVarObj = NewCallObject(cx, &script->bindings, *initialVarObj, NULL); + initialVarObj = NewCallObject(cx, &script->bindings, *initialVarObj, NULL, ORIGIN_EXEC); if (!initialVarObj) return false; initialVarObj->setPrivate(frame.fp()); @@ -1300,7 +1284,7 @@ DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp) AutoFunctionCallProbe callProbe(cx, evalfun, caller->script()); JSObject *scopeChain = - GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH); + GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH, ORIGIN_DEVAL); if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain)) return false; cx->regs->sp = vp + 1; @@ -1353,7 +1337,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen) sp[-1].setObject(*obj); } - JSObject *parent = GetScopeChainFast(cx, fp, op, oplen); + JSObject *parent = GetScopeChainFast(cx, fp, op, oplen, ORIGIN_WITH); if (!parent) return JS_FALSE; @@ -4713,7 +4697,7 @@ BEGIN_CASE(JSOP_FUNCALL) atoms = script->atomMap.vector; /* Now that the new frame is rooted, maybe create a call object. */ - if (newfun->isHeavyweight() && !js_GetCallObject(cx, regs.fp)) + if (newfun->isHeavyweight() && !js_GetCallObject(cx, regs.fp, ORIGIN_INTERP)) goto error; inlineCallCount++; @@ -5377,7 +5361,7 @@ BEGIN_CASE(JSOP_DEFFUN) } else { JS_ASSERT(!fun->isFlatClosure()); - obj2 = GetScopeChainFast(cx, regs.fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH); + obj2 = GetScopeChainFast(cx, regs.fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH, ORIGIN_DEFFUN); if (!obj2) goto error; } @@ -5516,7 +5500,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN) goto error; } else { JSObject *parent = GetScopeChainFast(cx, regs.fp, JSOP_DEFLOCALFUN, - JSOP_DEFLOCALFUN_LENGTH); + JSOP_DEFLOCALFUN_LENGTH, ORIGIN_DEFLOCALFUN); if (!parent) goto error; @@ -5679,7 +5663,7 @@ BEGIN_CASE(JSOP_LAMBDA) } #endif } else { - parent = GetScopeChainFast(cx, regs.fp, JSOP_LAMBDA, JSOP_LAMBDA_LENGTH); + parent = GetScopeChainFast(cx, regs.fp, JSOP_LAMBDA, JSOP_LAMBDA_LENGTH, ORIGIN_LAMBDA); if (!parent) goto error; } diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 2b90948b0c05..adb29d940300 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -811,10 +811,10 @@ GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen); * must reflect at runtime. */ extern JSObject * -GetScopeChain(JSContext *cx, JSStackFrame *fp); +GetScopeChain(JSContext *cx, JSStackFrame *fp, Origins); extern JSObject * -GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen); +GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen, Origins); /* * Report an error that the this value passed as |this| in the given arguments @@ -834,7 +834,7 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp); template bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v); -void +inline void PutActivationObjects(JSContext *cx, JSStackFrame *fp); /* diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 8f17777f468a..e45e9577b287 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -524,6 +524,19 @@ struct AutoInterpPreparer { } }; +inline void +PutActivationObjects(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame()); + + /* The order is important as js_PutCallObject needs to access argsObj. */ + if (fp->hasCallObj()) { + js_PutCallObject(cx, fp); + } else if (fp->hasArgsObj()) { + js_PutArgsObject(cx, fp); + } +} + class InvokeSessionGuard { InvokeArgsGuard args_; @@ -722,6 +735,8 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok) JS_ASSERT(fp->hasCallObj()); JS_ASSERT(fp->callObj().callIsForEval()); js_PutCallObject(cx, fp); + } else if (fp->hasCallObj()) { + fp->callObj().setSkipped(); } } else { /* @@ -732,6 +747,8 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok) if (fp->isFunctionFrame() && !fp->isYielding()) { JS_ASSERT_IF(fp->hasCallObj(), !fp->callObj().callIsForEval()); PutActivationObjects(cx, fp); + } else if (fp->hasCallObj()) { + fp->callObj().setSkipped(); } } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 27d59fa02121..070edbf4be3b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -287,6 +287,31 @@ namespace nanojit { class ValidateWriter; } +// TEMPORARY CRASH-FINDING +enum Origins { + ORIGIN_ON_TRACE = 1, + ORIGIN_EXEC = 2, + ORIGIN_GET_FRAME_OBJ = 3, + ORIGIN_INVOKE = 4, + ORIGIN_INTERP = 5, + ORIGIN_GET_SCOPE_CHAIN_API = 6, + ORIGIN_CLONE_FUNOBJ = 7, + ORIGIN_GET_FRAME_SCOPE_CHAIN = 8, + ORIGIN_WESC = 9, + ORIGIN_DEVAL = 10, + ORIGIN_WITH = 11, + ORIGIN_DEFFUN = 12, + ORIGIN_DEFLOCALFUN = 13, + ORIGIN_LAMBDA = 14, + ORIGIN_LAME = 15, + ORIGIN_MJIT_DEFFUN = 16, + ORIGIN_MJIT_DEFLOCALFUN = 17, + ORIGIN_MJIT_LAMBDA = 18, + ORIGIN_COMPILE_FUNCTION = 19, + ORIGIN_UIC = 20, + ORIGIN_MJIT_GCO = 21 +}; + /* * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets, * 64 bytes on 64-bit systems. The JSFunction struct is an extension of this @@ -386,9 +411,23 @@ struct JSObject : js::gc::Cell { HAS_EQUALITY = 0x200, METHOD_THRASH_COUNT_MASK = 0xc00, METHOD_THRASH_COUNT_SHIFT = 10, - METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT + METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT, + + ORIGIN_MASK = 0xff000000, + ORIGIN_SHIFT = 24, + SKIPPED_BIT = 0x00100000 + }; + // TMP CRASH-FINDING + void setOrigin(Origins origin) { + flags = (flags & ~(uint32)ORIGIN_MASK) | (origin << ORIGIN_SHIFT); + } + + void setSkipped() { + flags |= SKIPPED_BIT; + } + /* * Impose a sane upper bound, originally checked only for dense arrays, on * number of slots in an object. diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 8922439f4959..a458cc66cb81 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1681,7 +1681,7 @@ static JSObject * GetXMLScopeChain(JSContext *cx) { if (JSStackFrame *fp = js_GetTopStackFrame(cx)) - return GetScopeChain(cx, fp); + return GetScopeChain(cx, fp, ORIGIN_LAME); /* * There is no code active on this context. In place of an actual scope diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index f1394e1ccaa9..9aab6b621e73 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -325,7 +325,7 @@ stubs::CompileFunction(VMFrame &f, uint32 nactual) f.regs.sp = fp->base(); f.regs.pc = script->code; - if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp, ORIGIN_COMPILE_FUNCTION)) THROWV(NULL); CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT); @@ -368,7 +368,7 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint JS_ASSERT(newfp == f.regs.fp); /* Scope with a call object parented by callee's parent. */ - if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp)) + if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp, ORIGIN_UIC)) return false; /* Try to compile if not already compiled. */ @@ -588,7 +588,7 @@ void JS_FASTCALL stubs::GetCallObject(VMFrame &f) { JS_ASSERT(f.fp()->fun()->isHeavyweight()); - if (!js_GetCallObject(f.cx, f.fp())) + if (!js_GetCallObject(f.cx, f.fp(), ORIGIN_MJIT_GCO)) THROW(); } diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index abaffd825355..1eb010ee1c4e 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -725,7 +725,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun) } else { JS_ASSERT(!fun->isFlatClosure()); - obj2 = GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH); + obj2 = GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH, ORIGIN_MJIT_DEFFUN); if (!obj2) THROW(); } @@ -1386,7 +1386,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun) THROWV(NULL); } else { JSObject *parent = GetScopeChainFast(f.cx, f.fp(), JSOP_DEFLOCALFUN, - JSOP_DEFLOCALFUN_LENGTH); + JSOP_DEFLOCALFUN_LENGTH, ORIGIN_MJIT_DEFLOCALFUN); if (!parent) THROWV(NULL); @@ -1515,7 +1515,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun) if (FUN_NULL_CLOSURE(fun)) { parent = &f.fp()->scopeChain(); } else { - parent = GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH); + parent = GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH, ORIGIN_MJIT_LAMBDA); if (!parent) THROWV(NULL); }