Luke Wagner – Bug 634542 - Temporary diagnostic patch 2 (r=dvander,a=shaver)
authorLuke Wagner <lw@mozilla.com>
Fri, 18 Feb 2011 18:38:10 -0800
changeset 62855 5dd4f10fb1fdac79319254e66c36cf652861b068
parent 62854 9d6f665f7f845e3b21ded0516105eded6b0df8cd
child 62856 657c2a92ee2be94a442f9efb5894eb44f68616af
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersdvander, shaver
bugs634542
milestone2.0b12pre
Luke Wagner – Bug 634542 - Temporary diagnostic patch 2 (r=dvander,a=shaver)
js/src/jsapi.cpp
js/src/jsdbgapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsobj.h
js/src/jsxml.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/StubCalls.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4184,17 +4184,17 @@ JS_NewFunctionById(JSContext *cx, JSNati
 
 JS_PUBLIC_API(JSObject *)
 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
 {
     CHECK_REQUEST(cx);
     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);
     }
 
     if (funobj->getClass() != &js_FunctionClass) {
         /*
          * We cannot clone this object, so fail (we used to return funobj, bad
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1390,17 +1390,17 @@ JS_GetFrameScopeChain(JSContext *cx, JSS
     JS_ASSERT(cx->stack().contains(fp));
 
     js::AutoCompartment ac(cx, &fp->scopeChain());
     if (!ac.enter())
         return NULL;
 
     /* 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 *)
 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
 {
     JS_ASSERT(cx->stack().contains(fp));
 
     if (!fp->isFunctionFrame())
@@ -1412,17 +1412,17 @@ JS_GetFrameCallObject(JSContext *cx, JSS
 
     /* Force creation of argument object if not yet created */
     (void) js_GetArgsObject(cx, 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)
 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv)
 {
     if (fp->isDummyFrame())
         return false;
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -354,17 +354,17 @@ WrapEscapingClosure(JSContext *cx, JSSta
 
     /*
      * We do not attempt to reify Call and Block objects on demand for outer
      * scopes. This could be done (see the "v8" patch in bug 494235) but it is
      * fragile in the face of ongoing compile-time optimization. Instead, the
      * _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;
 
     JSObject *wfunobj = NewFunction(cx, scopeChain);
     if (!wfunobj)
         return NULL;
     AutoObjectRooter tvr(cx, wfunobj);
 
@@ -943,17 +943,18 @@ CalleeGetter(JSContext *cx, JSObject *ob
 
 namespace js {
 
 /*
  * Construct a call object for the given bindings.  The callee is the function
  * 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;
     gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
 
     JSObject *callobj = js_NewGCObject(cx, kind);
     if (!callobj)
         return NULL;
@@ -972,16 +973,17 @@ NewCallObject(JSContext *cx, Bindings *b
         if (s.slot != SHAPE_INVALID_SLOT) {
             JS_ASSERT(s.slot + 1 == callobj->slotSpan());
             break;
         }
     }
 #endif
 
     callobj->setCallObjCallee(callee);
+    callobj->setOrigin(origin);
     return callobj;
 }
 
 } // namespace js
 
 static inline JSObject *
 NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
 {
@@ -990,27 +992,23 @@ NewDeclEnvObject(JSContext *cx, JSStackF
         return NULL;
 
     envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
     envobj->setMap(cx->compartment->emptyDeclEnvShape);
     return envobj;
 }
 
 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();
     if (clasp == &js_WithClass || clasp == &js_BlockClass)
         JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
     else if (clasp == &js_CallClass)
         JS_ASSERT(fp->scopeChain().getPrivate() != fp);
 #endif
@@ -1035,17 +1033,17 @@ js_GetCallObject(JSContext *cx, JSStackF
                                      CalleeGetter, NULL,
                                      JSPROP_PERMANENT | JSPROP_READONLY,
                                      0, 0, NULL)) {
             return NULL;
         }
     }
 
     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;
 
     callobj->setPrivate(fp);
     JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
 
     /*
      * Push callobj on the top of the scope chain, and make it the
@@ -1056,17 +1054,17 @@ js_GetCallObject(JSContext *cx, JSStackF
 }
 
 JSObject * JS_FASTCALL
 js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
 {
     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,
                      0, nanojit::ACCSET_STORE_ANY)
 
 inline static void
 CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
 {
@@ -1368,34 +1366,77 @@ call_resolve(JSContext *cx, JSObject *ob
         *objp = obj;
         return true;
     }
 
     /* Control flow reaches here only if id was not resolved. */
     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;
+
+        // 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
          * Collector, which currently lacks a non-stub Unlink implementation
          * for JS objects (including Call objects), so is unable to collect
          * cycles involving Call objects whose frames are active without this
          * hiding hack.
          */
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -323,17 +323,18 @@ namespace js {
 
 /*
  * Construct a call object for the given bindings.  If this is a call object
  * for a function invocation, callee should be the function being called.
  * Otherwise it must be a call object for eval of strict mode code, and callee
  * 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.
  */
 #define VALUE_IS_FUNCTION(cx, v)                                              \
     (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction())
 
 static JS_ALWAYS_INLINE bool
@@ -511,17 +512,17 @@ js_ValueToFunctionObject(JSContext *cx, 
 
 extern JSObject *
 js_ValueToCallableObject(JSContext *cx, js::Value *vp, uintN flags);
 
 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);
 
 extern void
 js_PutCallObject(JSContext *cx, JSStackFrame *fp);
 
 extern JSBool JS_FASTCALL
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -105,32 +105,16 @@ using namespace js::gc;
 
 /* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
 #if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
 
 #ifdef DEBUG
 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)
 {
     JS_ASSERT_IF(next, next->prev_ == this);
     JS_ASSERT(cx->containingSegment(this) != NULL);
 
     JSFrameRegs *regs;
     if (cx->regs) {
@@ -260,17 +244,17 @@ js::GetBlockChainFast(JSContext *cx, JSS
  * current), place them at the head of scopeChain, and use that for the
  * closure's scope chain.  If we never close over a lexical block, we never
  * place a mutable clone of it on scopeChain.
  *
  * This lazy cloning is implemented in GetScopeChain, which is also used in
  * 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;
 
     if (!sharedBlock) {
         /*
          * Don't force a call object for a lightweight function call, but do
          * insist that there is a call object for a heavyweight function call.
          */
@@ -288,17 +272,17 @@ GetScopeChainFull(JSContext *cx, JSStack
      * if this frame is a call frame.
      *
      * Also, identify the innermost compiler-allocated block we needn't clone.
      */
     JSObject *limitBlock, *limitClone;
     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. */
         limitBlock = limitClone = NULL;
     } else {
         /*
          * scopeChain includes all blocks whose static scope we're within that
          * have already been cloned.  Find the innermost such block.  Its
@@ -381,25 +365,25 @@ GetScopeChainFull(JSContext *cx, JSStack
                  sharedBlock);
 
     /* Place our newly cloned blocks at the head of the scope chain.  */
     fp->setScopeChainNoCallObj(*innermostNewChild);
     return innermostNewChild;
 }
 
 JSObject *
-js::GetScopeChain(JSContext *cx, JSStackFrame *fp)
-{
-    return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp));
+js::GetScopeChain(JSContext *cx, JSStackFrame *fp, Origins origin)
+{
+    return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp), origin);
 }
 
 JSObject *
-js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
-{
-    return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen));
+js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen, Origins origin)
+{
+    return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen), origin);
 }
 
 /* Some objects (e.g., With) delegate 'this' to another object. */
 static inline JSObject *
 CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv)
 {
     JSObject *thisp = obj->thisObject(cx);
     if (!thisp)
@@ -704,17 +688,17 @@ Invoke(JSContext *cx, const CallArgs &ar
     JSStackFrame *fp = frame.fp();
     fp->initCallFrame(cx, callee, fun, args.argc(), flags);
     SetValueRangeToUndefined(fp->slots(), script->nfixed);
 
     /* Officially push fp. frame's destructor pops. */
     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. */
     JSBool ok;
     {
         AutoPreserveEnumerators preserve(cx);
         ok = RunScript(cx, script, fp);
     }
@@ -944,17 +928,17 @@ Execute(JSContext *cx, JSObject *chain, 
     }
 
     /*
      * Strict mode eval code receives its own, fresh lexical environment; thus
      * strict mode eval can't mutate its calling frame's binding set.
      */
     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());
 
         /* Clear the Call object propagated from the previous frame, if any. */
         if (frame.fp()->hasCallObj())
             frame.fp()->clearCallObj();
         frame.fp()->setScopeChainAndCallObj(*initialVarObj);
@@ -1295,17 +1279,17 @@ DirectEval(JSContext *cx, JSFunction *ev
     JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun);
     JS_ASSERT(IsBuiltinEvalFunction(evalfun));
 
     JSStackFrame *caller = cx->fp();
     JS_ASSERT(caller->isScriptFrame());
     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;
     return true;
 }
 
 bool
 ValueToId(JSContext *cx, const Value &v, jsid *idp)
@@ -1348,17 +1332,17 @@ js_EnterWith(JSContext *cx, jsint stackI
         obj = &sp[-1].toObject();
     } else {
         obj = js_ValueToNonNullObject(cx, sp[-1]);
         if (!obj)
             return JS_FALSE;
         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;
 
     OBJ_TO_INNER_OBJECT(cx, obj);
     if (!obj)
         return JS_FALSE;
 
     JSObject *withobj = js_NewWithObject(cx, obj, parent,
@@ -4708,17 +4692,17 @@ BEGIN_CASE(JSOP_FUNCALL)
 
             /* Refresh interpreter locals. */
             JS_ASSERT(newfp == regs.fp);
             script = newscript;
             argv = regs.fp->formalArgsEnd() - newfun->nargs;
             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++;
             JS_RUNTIME_METER(rt, inlineCalls);
 
             TRACE_0(EnterFrame);
 
             CHECK_INTERRUPT_HANDLER();
@@ -5372,17 +5356,17 @@ BEGIN_CASE(JSOP_DEFFUN)
          * Even a null closure needs a parent for principals finding.
          * FIXME: bug 476950, although debugger users may also demand some kind
          * of scope link for debugger-assisted eval-in-frame.
          */
         obj2 = &regs.fp->scopeChain();
     } 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;
     }
 
     /*
      * If static link is not current scope, clone fun's object to link to the
      * current scope via parent. We do this to enable sharing of compiled
      * functions among multiple equivalent scopes, amortizing the cost of
@@ -5511,17 +5495,17 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
     JSObject *obj = FUN_OBJECT(fun);
 
     if (FUN_NULL_CLOSURE(fun)) {
         obj = CloneFunctionObject(cx, fun, &regs.fp->scopeChain());
         if (!obj)
             goto error;
     } else {
         JSObject *parent = GetScopeChainFast(cx, regs.fp, JSOP_DEFLOCALFUN,
-                                             JSOP_DEFLOCALFUN_LENGTH);
+                                             JSOP_DEFLOCALFUN_LENGTH, ORIGIN_DEFLOCALFUN);
         if (!parent)
             goto error;
 
         if (obj->getParent() != parent) {
 #ifdef JS_TRACER
             if (TRACE_RECORDER(cx))
                 AbortRecording(cx, "DEFLOCALFUN for closure");
 #endif
@@ -5674,17 +5658,17 @@ BEGIN_CASE(JSOP_LAMBDA)
                     h.add(p, fun, 1);
                 } else {
                     JS_ASSERT(p->key == fun);
                     ++p->value;
                 }
             }
 #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;
         }
 
         obj = CloneFunctionObject(cx, fun, parent);
         if (!obj)
             goto error;
     } while (0);
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -806,20 +806,20 @@ GetBlockChainFast(JSContext *cx, JSStack
 /*
  * Refresh and return fp->scopeChain.  It may be stale if block scopes are
  * active but not yet reflected by objects in the scope chain.  If a block
  * scope contains a with, eval, XML filtering predicate, or similar such
  * dynamically scoped construct, then compile-time block scope at fp->blocks
  * 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
  * vector is not compatible with the specified class.
  */
 void
 ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp);
 
@@ -829,17 +829,17 @@ ReportIncompatibleMethod(JSContext *cx, 
  * of |this|. If |this| is an object, insist that it be an instance of the
  * appropriate wrapper class for T, and set |*v| to its private slot value.
  * If |this| is a primitive, unbox it into |*v| if it's of the required
  * type, and throw an error otherwise.
  */
 template <typename T>
 bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v);
 
-void
+inline void
 PutActivationObjects(JSContext *cx, JSStackFrame *fp);
 
 /*
  * For a call's vp (which necessarily includes callee at vp[0] and the original
  * specified |this| at vp[1]), convert null/undefined |this| into the global
  * object for the callee and replace other primitives with boxed versions. The
  * callee must not be strict mode code.
  */
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -519,16 +519,29 @@ struct AutoInterpPreparer  {
     }
 
     ~AutoInterpPreparer()
     {
         --cx->interpLevel;
     }
 };
 
+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_;
     InvokeFrameGuard frame_;
     Value savedCallee_, savedThis_;
     Value *formals_, *actuals_;
     unsigned nformals_;
     JSScript *script_;
@@ -717,26 +730,30 @@ ScriptEpilogue(JSContext *cx, JSStackFra
          * parent frame has it).
          */
         if (fp->script()->strictModeCode) {
             JS_ASSERT(!fp->isYielding());
             JS_ASSERT(!fp->hasArgsObj());
             JS_ASSERT(fp->hasCallObj());
             JS_ASSERT(fp->callObj().callIsForEval());
             js_PutCallObject(cx, fp);
+        } else if (fp->hasCallObj()) {
+            fp->callObj().setSkipped();
         }
     } else {
         /*
          * Otherwise only function frames have activation objects. A yielding
          * frame's activation objects are transferred to the floating frame,
          * stored in the generator, and thus need not be synced.
          */
         if (fp->isFunctionFrame() && !fp->isYielding()) {
             JS_ASSERT_IF(fp->hasCallObj(), !fp->callObj().callIsForEval());
             PutActivationObjects(cx, fp);
+        } else if (fp->hasCallObj()) {
+            fp->callObj().setSkipped();
         }
     }
 
     /*
      * If inline-constructing, replace primitive rval with the new object
      * passed in via |this|, and instrument this constructor invocation.
      */
     if (fp->isConstructing() && ok) {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -282,16 +282,41 @@ struct NativeIterator;
 }
 
 struct JSFunction;
 
 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
  * struct allocated from a larger GC size-class.
  *
  * The clasp member stores the js::Class pointer for this object. We do *not*
  * synchronize updates of clasp or flags -- API clients must take care.
  *
@@ -381,19 +406,33 @@ struct JSObject : js::gc::Cell {
         GENERIC                   =  0x10,
         METHOD_BARRIER            =  0x20,
         INDEXED                   =  0x40,
         OWN_SHAPE                 =  0x80,
         BOUND_FUNCTION            = 0x100,
         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.
      */
     enum {
         NSLOTS_BITS     = 29,
         NSLOTS_LIMIT    = JS_BIT(NSLOTS_BITS)
     };
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -1676,17 +1676,17 @@ GetXMLSettingFlags(JSContext *cx, uintN 
             *flagsp |= JS_BIT(n);
     return true;
 }
 
 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
      * chain, use the context's global object, which is set in
      * s_InitFunctionAndObjectClasses, and which represents the default scope
      * chain for the embedding. See also js_FindClassObject.
      *
      * For embeddings that use the inner and outer object hooks, the inner
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -320,17 +320,17 @@ stubs::CompileFunction(VMFrame &f, uint3
     /* Finish frame initialization. */
     fp->initCallFrameLatePrologue();
 
     /* These would have been initialized by the prologue. */
     f.regs.fp = fp;
     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);
     if (status == Compile_Okay)
         return script->getJIT(fp->isConstructing())->invokeEntry;
 
     /* Function did not compile... interpret it. */
     JSBool ok = Interpret(cx, fp);
@@ -363,17 +363,17 @@ UncachedInlineCall(VMFrame &f, uint32 fl
     newfp->initCallFrame(cx, callee, newfun, argc, flags);
     SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
 
     /* Officially push the frame. */
     stack.pushInlineFrame(cx, newscript, newfp, &f.regs);
     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. */
     if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
         CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter);
         if (status == Compile_Error) {
             /* A runtime exception was thrown, get out. */
             InlineReturn(f);
@@ -583,17 +583,17 @@ js_InternalThrow(VMFrame &f)
     JSScript *script = fp->script();
     return script->nativeCodeForPC(fp->isConstructing(), pc);
 }
 
 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();
 }
 
 void JS_FASTCALL
 stubs::CreateThis(VMFrame &f, JSObject *proto)
 {
     JSContext *cx = f.cx;
     JSStackFrame *fp = f.fp();
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -720,17 +720,17 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
          * Even a null closure needs a parent for principals finding.
          * FIXME: bug 476950, although debugger users may also demand some kind
          * of scope link for debugger-assisted eval-in-frame.
          */
         obj2 = &fp->scopeChain();
     } 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();
     }
 
     /*
      * If static link is not current scope, clone fun's object to link to the
      * current scope via parent. We do this to enable sharing of compiled
      * functions among multiple equivalent scopes, amortizing the cost of
@@ -1381,17 +1381,17 @@ stubs::DefLocalFun(VMFrame &f, JSFunctio
     JSObject *obj = FUN_OBJECT(fun);
 
     if (FUN_NULL_CLOSURE(fun)) {
         obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain());
         if (!obj)
             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);
 
         if (obj->getParent() != parent) {
             obj = CloneFunctionObject(f.cx, fun, parent);
             if (!obj)
                 THROWV(NULL);
         }
@@ -1510,17 +1510,17 @@ JSObject * JS_FASTCALL
 stubs::Lambda(VMFrame &f, JSFunction *fun)
 {
     JSObject *obj = FUN_OBJECT(fun);
 
     JSObject *parent;
     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);
     }
 
     obj = CloneFunctionObject(f.cx, fun, parent);
     if (!obj)
         THROWV(NULL);