Backed out changeset 062ea62f9bda (backed out bug 488203 again).
authorAndreas Gal <gal@mozilla.com>
Thu, 16 Apr 2009 12:18:46 -0700
changeset 27468 4273c0708552544e8a0317e84c02e515b0a02476
parent 27467 062ea62f9bda22be55d94c71dc98e780d91342e6
child 27470 5e56592a8d89854b3452f76ce9465828dfee98ed
push id6576
push userrsayre@mozilla.com
push dateSat, 18 Apr 2009 15:37:12 +0000
treeherderautoland@55d20693b9cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs488203
milestone1.9.2a1pre
backs out062ea62f9bda22be55d94c71dc98e780d91342e6
Backed out changeset 062ea62f9bda (backed out bug 488203 again).
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jstracer.cpp
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4388,18 +4388,25 @@ js_Interpret(JSContext *cx)
             OBJ_SET_SLOT(cx, fp->varobj, slot, rval);
             len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
             JS_ASSERT(len == js_CodeSpec[op].length);
             DO_NEXT_OP(len);
           }
 
 #define COMPUTE_THIS(cx, fp, obj)                                             \
     JS_BEGIN_MACRO                                                            \
-        if (!(obj = js_ComputeThisForFrame(cx, fp)))                          \
-            goto error;                                                       \
+        if (fp->flags & JSFRAME_COMPUTED_THIS) {                              \
+            obj = fp->thisp;                                                  \
+        } else {                                                              \
+            obj = js_ComputeThis(cx, JS_TRUE, fp->argv);                      \
+            if (!obj)                                                         \
+                goto error;                                                   \
+            fp->thisp = obj;                                                  \
+            fp->flags |= JSFRAME_COMPUTED_THIS;                               \
+        }                                                                     \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_THIS)
             COMPUTE_THIS(cx, fp, obj);
             PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_THIS)
 
           BEGIN_CASE(JSOP_GETTHISPROP)
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -460,29 +460,16 @@ js_ComputeThis(JSContext *cx, JSBool laz
 
 extern const uint16 js_PrimitiveTestFlags[];
 
 #define PRIMITIVE_THIS_TEST(fun,thisv)                                        \
     (JS_ASSERT(!JSVAL_IS_VOID(thisv)),                                        \
      JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags),                        \
                       js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1]))
 
-static inline JSObject *
-js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp)
-{
-    if (fp->flags & JSFRAME_COMPUTED_THIS)
-        return fp->thisp;
-    JSObject* obj = js_ComputeThis(cx, JS_TRUE, fp->argv);
-    if (!obj)
-        return NULL;
-    fp->thisp = obj;
-    fp->flags |= JSFRAME_COMPUTED_THIS;
-    return obj;
-}
-
 /*
  * NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp
  * is non-null), and that vp points to the callee, |this| parameter, and
  * actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last
  * JS stack segment that js_AllocStack allocated. The function may use the
  * space available after vp + 2 + argc in the stack segment for temporaries,
  * so the caller should not use that space for values that must be preserved
  * across the call.
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1738,21 +1738,19 @@ skip:
             }
             // Skip over stopFrame itself.
             JS_ASSERT(n != 0);
             --n;
             fp = fp->down;
         }
         for (; n != 0; fp = fp->down) {
             --n;
-            if (fp->callee) {
+            if (fp->callee) { // might not have it if the entry frame is global
                 JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1]));
                 fp->thisp = JSVAL_TO_OBJECT(fp->argv[-1]);
-                if (fp->flags & JSFRAME_CONSTRUCTING) // constructors always compute 'this'
-                    fp->flags |= JSFRAME_COMPUTED_THIS;
             }
         }
     }
     debug_only_v(printf("\n");)
     return mp - mp_base;
 }
 
 /* Emit load instructions onto the trace that read the initial stack state. */
@@ -3387,17 +3385,17 @@ js_SynthesizeFrame(JSContext* cx, const 
     newifp->frame.scopeChain = OBJ_GET_PARENT(cx, fi.callee);
     newifp->frame.sharpDepth = 0;
     newifp->frame.sharpArray = NULL;
     newifp->frame.flags = constructing ? JSFRAME_CONSTRUCTING : 0;
     newifp->frame.dormantNext = NULL;
     newifp->frame.xmlNamespace = NULL;
     newifp->frame.blockChain = NULL;
     newifp->mark = newmark;
-    newifp->frame.thisp = NULL; // will be updated in FlushNativeStackFrame
+    newifp->frame.thisp = NULL; // will be set by js_ExecuteTree -> FlushNativeStackFrame
 
     newifp->frame.regs = fp->regs;
     newifp->frame.regs->pc = script->code;
     newifp->frame.regs->sp = newsp + script->nfixed;
     newifp->frame.imacpc = NULL;
     newifp->frame.slots = newsp;
     if (script->staticLevel < JS_DISPLAY_SIZE) {
         JSStackFrame **disp = &cx->display[script->staticLevel];
@@ -4345,16 +4343,18 @@ LeaveTree(InterpState& state, VMSideExit
                               getStackTypeMap(innermost),
                               stack, NULL);
     JS_ASSERT(unsigned(slots) == innermost->numStackSlots);
 
 #ifdef DEBUG
     // Verify that our state restoration worked.
     for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) {
         JS_ASSERT_IF(fp->callee, JSVAL_IS_OBJECT(fp->argv[-1]));
+        JS_ASSERT_IF(fp->callee && fp->thisp != JSVAL_TO_OBJECT(fp->argv[-1]),
+                     !(fp->flags & JSFRAME_COMPUTED_THIS) && !fp->thisp);
     }
 #endif
 #ifdef JS_JIT_SPEW
     if (innermost->exitType != TIMEOUT_EXIT)
         AUDIT(sideExitIntoInterpreter);
     else
         AUDIT(timeoutIntoInterpreter);
 #endif
@@ -6234,42 +6234,23 @@ TraceRecorder::unbox_jsval(jsval v, LIns
         v_ins = lir->ins2(LIR_piand, v_ins, INS_CONST(~JSVAL_TAGMASK));
         return;
     }
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::getThis(LIns*& this_ins)
 {
-    JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp);
-    if (!thisObj)
-        ABORT_TRACE("js_ComputeThis failed");
-    if (!cx->fp->callee || JSVAL_IS_NULL(cx->fp->argv[-1])) {
-        JS_ASSERT(callDepth == 0);
-        /*
-         * In global code, or if this is NULL, wrap the global object and bake it directly
-         * into the trace.
-         */
-        this_ins = INS_CONSTPTR(thisObj);
-        set(&cx->fp->argv[-1], this_ins);
-        return true;
-    }
-    this_ins = get(&cx->fp->argv[-1]);
-
-    /*
-     * When we inline through scripted functions, we have already previously touched the 'this'
-     * object and hence it is already guaranteed to be wrapped. Otherwise we have to explicitly
-     * check that the object has been wrapped. If not, we side exit and let the interpreter
-     * wrap it.
-     */
-    if (callDepth == 0) {
-        LIns* map_ins = lir->insLoad(LIR_ldp, this_ins, (int)offsetof(JSObject, map));
-        LIns* ops_ins = lir->insLoad(LIR_ldp, map_ins, (int)offsetof(JSObjectMap, ops));
-        LIns* op_ins = lir->insLoad(LIR_ldp, ops_ins, (int)offsetof(JSObjectOps, thisObject));
-        guard(true, lir->ins_eq0(op_ins), MISMATCH_EXIT);
+    if (cx->fp->callee) { /* in a function */
+        if (JSVAL_IS_NULL(cx->fp->argv[-1]))
+            return false;
+        this_ins = get(&cx->fp->argv[-1]);
+        guard(false, lir->ins_eq0(this_ins), MISMATCH_EXIT);
+    } else { /* in global code */
+        this_ins = scopeChain();
     }
     return true;
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp, LIns* exit)
 {
     bool cond = STOBJ_GET_CLASS(obj) == clasp;