Merge. Lame.
authorAndreas Gal <gal@mozilla.com>
Wed, 13 Aug 2008 17:13:53 -0700
changeset 18148 e4548362fa74e5449c76dcda675959130cf8f863
parent 18147 3b57c7a92f7488b0d268551e3549cde3716da774 (current diff)
parent 18146 9379f9e865f7ff5edaed99180ee2bd885d8689c2 (diff)
child 18149 baac751c4bf54243cdeb047afe121381b9a71a88
child 18154 f8033bfacfbbab4a70cc0f5c616656a412c830df
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a2pre
Merge. Lame.
js/src/jstracer.cpp
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -249,40 +249,16 @@ Oracle::markStackSlotUndemotable(JSScrip
 bool 
 Oracle::isStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) const
 {
     uint32 hash = uint32(ip) + (slot << 5);
     hash %= ORACLE_SIZE;
     return _dontDemote.get(hash);
 }
 
-/* Calculate the total number of native frame slots we need from this frame
-   all the way back to the entry frame, including the current stack usage. */
-static unsigned
-nativeStackSlots(unsigned callDepth, JSStackFrame* fp)
-{
-    unsigned slots = 0;
-    for (;;) {
-        unsigned operands = fp->regs->sp - StackBase(fp);
-        JS_ASSERT(operands <= fp->script->nslots - fp->script->nfixed);
-        slots += operands;
-        if (fp->callee)
-            slots += fp->script->nfixed;
-        if (callDepth-- == 0) {
-            if (fp->callee) {
-                unsigned nargs = JS_MAX(fp->fun->nargs, fp->argc);
-                slots += 1/*this*/ + nargs;
-            }
-            return slots;
-        }
-        fp = fp->down;
-    }
-    JS_NOT_REACHED("nativeStackSlots");
-}
-
 static LIns* demote(LirWriter *out, LInsp i)
 {
     if (i->isCall())
         return callArgN(i,0);
     if (i->isop(LIR_i2f) || i->isop(LIR_u2f))
         return i->oprnd1();
     if (i->isconst())
         return i;
@@ -558,16 +534,52 @@ public:
     JS_END_MACRO
 
 #define FORALL_SLOTS(cx, ngslots, gslots, callDepth, code)                    \
     JS_BEGIN_MACRO                                                            \
         FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, code);                       \
         FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code);                  \
     JS_END_MACRO
 
+/* Calculate the total number of native frame slots we need from this frame
+   all the way back to the entry frame, including the current stack usage. */
+static unsigned
+nativeStackSlots(JSContext *cx, unsigned callDepth, JSStackFrame* fp)
+{
+    unsigned slots = 0;
+#if defined _DEBUG
+    unsigned int origCallDepth = callDepth;
+#endif
+    for (;;) {
+        unsigned operands = fp->regs->sp - StackBase(fp);
+        JS_ASSERT(operands <= fp->script->nslots - fp->script->nfixed);
+        slots += operands;
+        if (fp->callee)
+            slots += fp->script->nfixed;
+        if (callDepth-- == 0) {
+            if (fp->callee) {
+                unsigned nargs = JS_MAX(fp->fun->nargs, fp->argc);
+                slots += 1/*this*/ + nargs;
+            }
+#if defined _DEBUG
+            unsigned int m = 0;
+            FORALL_SLOTS_IN_PENDING_FRAMES(cx, origCallDepth, m++);
+            JS_ASSERT(m == slots);
+#endif
+            return slots;
+        }
+        JSStackFrame* fp2 = fp;
+        fp = fp->down;
+        int missing = fp2->fun->nargs - fp2->argc;
+        if (missing > 0)
+            slots += missing;
+    }
+    JS_NOT_REACHED("nativeStackSlots");
+}
+
 /* Capture the typemap for the selected slots of the global object. */
 void
 TypeMap::captureGlobalTypes(JSContext* cx, SlotList& slots)
 {
     unsigned ngslots = slots.length();
     uint16* gslots = slots.data();
     setLength(ngslots);
     uint8* map = data();
@@ -579,17 +591,17 @@ TypeMap::captureGlobalTypes(JSContext* c
         *m++ = type;
     );
 }
 
 /* Capture the typemap for the currently pending stack frames. */
 void 
 TypeMap::captureStackTypes(JSContext* cx, unsigned callDepth)
 {
-    setLength(nativeStackSlots(callDepth, cx->fp));
+    setLength(nativeStackSlots(cx, callDepth, cx->fp));
     uint8* map = data();
     uint8* m = map;
     FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
         uint8 type = getCoercedType(*vp);
         if ((type == JSVAL_INT) && oracle.isStackSlotUndemotable(cx->fp->script,
                 cx->fp->regs->pc, unsigned(m - map)))
             type = JSVAL_DOUBLE;
         *m++ = type;
@@ -1151,17 +1163,17 @@ struct FrameInfo {
 
 SideExit*
 TraceRecorder::snapshot(ExitType exitType)
 {
     JSStackFrame* fp = cx->fp;
     if (exitType == BRANCH_EXIT && js_IsLoopExit(cx, fp->script, fp->regs->pc))
         exitType = LOOP_EXIT;
     /* generate the entry map and stash it in the trace */
-    unsigned stackSlots = nativeStackSlots(callDepth, fp);
+    unsigned stackSlots = nativeStackSlots(cx, callDepth, fp);
     /* its sufficient to track the native stack use here since all stores above the
        stack watermark defined by guards are killed. */
     trackNativeStackUse(stackSlots + 1);
     /* reserve space for the type map */
     unsigned ngslots = treeInfo->globalSlots.length();
     LIns* data = lir_buf_writer->skip((stackSlots + ngslots) * sizeof(uint8));
     /* setup side exit structure */
     memset(&exit, 0, sizeof(exit));
@@ -1581,17 +1593,17 @@ js_RecordTree(JSContext* cx, JSTraceMoni
     /* we shouldn't have any interned globals for a new tree */
     JS_ASSERT(!ti->globalSlots.length());
     
     /* capture the coerced type of each active slot in the stack type map */
     ti->stackTypeMap.captureStackTypes(cx, 0/*callDepth*/);
     
     /* determine the native frame layout at the entry point */
     unsigned entryNativeStackSlots = ti->stackTypeMap.length();
-    JS_ASSERT(entryNativeStackSlots == nativeStackSlots(0/*callDepth*/, cx->fp));
+    JS_ASSERT(entryNativeStackSlots == nativeStackSlots(cx, 0/*callDepth*/, cx->fp));
     ti->entryNativeStackSlots = entryNativeStackSlots;
     ti->nativeStackBase = (entryNativeStackSlots -
             (cx->fp->regs->sp - StackBase(cx->fp))) * sizeof(double);
     ti->maxNativeStackSlots = entryNativeStackSlots;
     ti->maxCallDepth = 0;
 
     /* create the list of global properties we want to intern */
     ti->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape;
@@ -1760,19 +1772,19 @@ js_ExecuteTree(JSContext* cx, Fragment* 
     cx->gcDontBlock = JS_FALSE;
 
     for (int32 i = 0; i < lr->calldepth; i++)
         js_SynthesizeFrame(cx, callstack[i]);
 
     SideExit* e = lr->exit;
     JSStackFrame* fp = cx->fp;
     JS_ASSERT((e->sp_adj / sizeof(double)) + ti->entryNativeStackSlots >=
-              nativeStackSlots(lr->calldepth, fp));
+              nativeStackSlots(cx, lr->calldepth, fp));
     fp->regs->sp += (e->sp_adj / sizeof(double)) + ti->entryNativeStackSlots -
-                    nativeStackSlots(lr->calldepth, fp);
+                    nativeStackSlots(cx, lr->calldepth, fp);
     fp->regs->pc = (jsbytecode*)lr->from->root->ip + e->ip_adj;
 
 #if defined(DEBUG) && defined(NANOJIT_IA32)
     printf("leaving trace at %s:%u@%u, exitType=%d, sp=%p, ip=%p, cycles=%llu\n",
            fp->script->filename, js_PCToLineNumber(cx, fp->script, fp->regs->pc),
            fp->regs->pc - fp->script->code,
            lr->exit->exitType,
            state.sp, lr->jmp,
@@ -3673,18 +3685,31 @@ TraceRecorder::prop(JSObject* obj, LIns*
         v_ins = lir->insImm(JSVAL_TO_BOOLEAN(JSVAL_VOID));
         JS_ASSERT(cs.ndefs == 1);
         stack(-cs.nuses, v_ins);
         return true;
     }
 
     /* Insist if setting on obj being the directly addressed object. */
     uint32 setflags = (cs.format & (JOF_SET | JOF_INCDEC));
-    if (setflags && obj2 != obj)
-        ABORT_TRACE("JOF_SET opcode hit prototype chain");
+    LIns* dslots_ins = NULL;
+    if (obj2 != obj) {
+        if (setflags)
+            ABORT_TRACE("JOF_SET opcode hit prototype chain");
+
+        /*
+         * We're getting a proto-property. Walk up the prototype chain emitting
+         * proto slot loads, updating obj as we go, leaving obj set to obj2 with
+         * obj_ins the last proto-load.
+         */
+        while (obj != obj2) {
+            obj_ins = stobj_get_slot(obj_ins, JSSLOT_PROTO, dslots_ins);
+            obj = STOBJ_GET_PROTO(obj);
+        }
+    }
 
     /* Don't trace getter or setter calls, our caller wants a direct slot. */
     if (PCVAL_IS_SPROP(pcval)) {
         JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
 
         if (setflags && !SPROP_HAS_STUB_SETTER(sprop))
             ABORT_TRACE("non-stub setter");
         if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
@@ -3708,17 +3733,16 @@ TraceRecorder::prop(JSObject* obj, LIns*
             ABORT_TRACE("no valid slot");
         slot = sprop->slot;
     } else {
         if (!PCVAL_IS_SLOT(pcval))
             ABORT_TRACE("PCE is not a slot");
         slot = PCVAL_TO_SLOT(pcval);
     }
 
-    LIns* dslots_ins = NULL;
     v_ins = stobj_get_slot(obj_ins, slot, dslots_ins);
     if (!unbox_jsval(STOBJ_GET_SLOT(obj, slot), v_ins))
         ABORT_TRACE("unboxing");
     return true;
 }
 
 bool
 TraceRecorder::elem(jsval& l, jsval& r, jsval*& vp, LIns*& v_ins, LIns*& addr_ins)