Merge, dammit!
authorBrendan Eich <brendan@mozilla.org>
Thu, 18 Dec 2008 22:40:58 -0800
changeset 23099 b8d8494faf18f57473b1b28d9c46964c63827343
parent 23098 db3662381be257b958b65061d8db879947c093d9 (current diff)
parent 22928 e98754e147eb16d00883cf104eb1dcc23bc89424 (diff)
child 23100 5af9839712f7f6d2be011763ce4a0370c1f7b5f5
push id4346
push userrsayre@mozilla.com
push dateFri, 26 Dec 2008 01:26:36 +0000
treeherdermozilla-central@8eb5a5b83a93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
Merge, dammit!
js/src/jsemit.cpp
js/src/jsobj.cpp
js/src/jsopcode.tbl
js/src/jstracer.cpp
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -826,18 +826,16 @@ array_defineProperty(JSContext *cx, JSOb
 
     if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))
         return JS_TRUE;
 
     isIndex = js_IdIsIndex(ID_TO_VALUE(id), &i);
     if (!isIndex || attrs != JSPROP_ENUMERATE) {
         if (!ENSURE_SLOW_ARRAY(cx, obj))
             return JS_FALSE;
-        if (isIndex && STOBJ_IS_DELEGATE(obj))
-            cx->runtime->anyArrayProtoHasElement = JS_TRUE;
         return js_DefineProperty(cx, obj, id, value, getter, setter, attrs, propp);
     }
 
     return array_setProperty(cx, obj, id, &value);
 }
 
 static JSBool
 array_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1700,17 +1700,16 @@ EmitIndexOp(JSContext *cx, JSOp op, uint
  * caller's lexical environment, and embedding a false return on error.
  */
 #define EMIT_INDEX_OP(op, index)                                              \
     JS_BEGIN_MACRO                                                            \
         if (!EmitIndexOp(cx, op, index, cg))                                  \
             return JS_FALSE;                                                  \
     JS_END_MACRO
 
-
 static JSBool
 EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     JSAtomListElement *ale;
 
     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     if (op == JSOP_GETPROP &&
         pn->pn_atom == cx->runtime->atomState.lengthAtom) {
@@ -2328,22 +2327,34 @@ EmitXMLName(JSContext *cx, JSParseNode *
         return JS_FALSE;
     }
 
     return js_Emit1(cx, cg, op) >= 0;
 }
 #endif
 
 static JSBool
+EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg);
+
+static JSBool
 EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
            JSBool callContext)
 {
     JSParseNode *pn2, *pndot, *pnup, *pndown;
     ptrdiff_t top;
 
+    /*
+     * Special case obj.__proto__ to deoptimize away from fast paths in the
+     * interpreter and trace recorder, which skip dense array instances by
+     * skipping over the directly referenced object to Array.prototype before
+     * looking up the property name. See bug 450274.
+     */
+    if (pn->pn_atom == cx->runtime->atomState.protoAtom)
+        return EmitElemOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
+
     pn2 = pn->pn_expr;
     if (callContext) {
         JS_ASSERT(pn->pn_type == TOK_DOT);
         JS_ASSERT(op == JSOP_GETPROP);
         op = JSOP_CALLPROP;
     } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
         if (pn2->pn_op == JSOP_THIS) {
             if (pn->pn_atom != cx->runtime->atomState.lengthAtom) {
@@ -5324,16 +5335,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
                 break;
               case TOK_DOT:
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                     return JS_FALSE;
                 if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {
                     if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)
                         return JS_FALSE;
+                } else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) {
+                    if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
+                        return JS_FALSE;
+                    if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
+                        return JS_FALSE;
                 } else {
                     EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);
                 }
                 break;
               case TOK_LB:
 #if JS_HAS_LVALUE_RETURN
               case TOK_LP:
 #endif
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -321,20 +321,30 @@ js_SetProtoOrParent(JSContext *cx, JSObj
                                  (slot == JSSLOT_PROTO) ? js_proto_str
                                                         : js_parent_str
 #endif
                                  );
         }
         return JS_FALSE;
     }
 
-    // Maintain the "any Array prototype has indexed properties hazard" flag.
+    /*
+     * Maintain the "any Array prototype has indexed properties hazard" flag by
+     * conservatively setting it. We simply don't know what pobj has in the way
+     * of indexed properties, either directly or along its prototype chain, and
+     * we won't expend effort here to find out. We do know that if obj is not
+     * an array or a prototype (delegate), then we're ok. And, of course, pobj
+     * must be non-null.
+     *
+     * This pessimistic approach could be improved, but setting __proto__ is
+     * quite rare and arguably deserving of deoptimization.
+     */
     if (slot == JSSLOT_PROTO &&
-        OBJ_IS_ARRAY(cx, pobj) &&
-        pobj->fslots[JSSLOT_ARRAY_LENGTH] != 0) {
+        pobj &&
+        (OBJ_IS_ARRAY(cx, obj) || OBJ_IS_DELEGATE(cx, obj))) {
         rt->anyArrayProtoHasElement = JS_TRUE;
     }
     return JS_TRUE;
 }
 
 static JSHashNumber
 js_hash_object(const void *key)
 {
@@ -3180,29 +3190,34 @@ js_DefineProperty(JSContext *cx, JSObjec
                                    0, 0, propp);
 }
 
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
  * nominal initial value of a slot-full property, while GC safety wants that
  * value to be stored before the call-out through the hook.  Optimize to do
  * both while saving cycles for classes that stub their addProperty hook.
+ *
+ * As in js_SetProtoOrParent (see above), we maintain the "any Array prototype
+ * has indexed properties hazard" flag by conservatively setting it.
  */
 #define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup)              \
     JS_BEGIN_MACRO                                                            \
         if ((clasp)->addProperty != JS_PropertyStub) {                        \
             jsval nominal_ = *(vp);                                           \
             if (!(clasp)->addProperty(cx, obj, SPROP_USERID(sprop), vp)) {    \
                 cleanup;                                                      \
             }                                                                 \
             if (*(vp) != nominal_) {                                          \
                 if (SPROP_HAS_VALID_SLOT(sprop, scope))                       \
                     LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *(vp));  \
             }                                                                 \
         }                                                                     \
+        if (STOBJ_IS_DELEGATE(obj) && JSID_IS_INT(sprop->id))                 \
+            cx->runtime->anyArrayProtoHasElement = JS_TRUE;                   \
     JS_END_MACRO
 
 JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
                         JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
                         uintN flags, intN shortid, JSProperty **propp)
 {
     JSClass *clasp;
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -536,16 +536,17 @@ OPDEF(JSOP_UNUSED219,     219,"unused219
  */
 OPDEF(JSOP_INDEXBASE1,    220,"atombase1",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE2,    221,"atombase2",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 OPDEF(JSOP_INDEXBASE3,    222,"atombase3",     NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 
 OPDEF(JSOP_CALLGVAR,      223, "callgvar",     NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLLOCAL,     224, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_CALLARG,       225, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
+
 OPDEF(JSOP_UNUSED226,     226, "unused226",    NULL,  1,  0,  1,  1,  JOF_BYTE)
 
 /*
  * Opcodes to hold 8-bit and 32-bit immediate integer operands.
  */
 OPDEF(JSOP_INT8,          227, "int8",         NULL,  2,  0,  1, 16,  JOF_INT8)
 OPDEF(JSOP_INT32,         228, "int32",        NULL,  5,  0,  1, 16,  JOF_INT32)
 
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -7758,17 +7758,16 @@ JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_GOTOX()
 {
     return true;
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_IFEQX()
 {
-    trackCfgMerges(cx->fp->regs->pc);
     return record_JSOP_IFEQ();
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_IFNEX()
 {
     return record_JSOP_IFNE();
 }
@@ -8452,17 +8451,17 @@ TraceRecorder::record_JSOP_INT32()
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_LENGTH()
 {
     jsval& l = stackval(-1);
     if (JSVAL_IS_PRIMITIVE(l)) {
         if (!JSVAL_IS_STRING(l))
-            ABORT_TRACE("non-string primitives unsupported");
+            ABORT_TRACE("non-string primitive JSOP_LENGTH unsupported");
         LIns* str_ins = get(&l);
         LIns* len_ins = lir->insLoad(LIR_ldp, str_ins, (int)offsetof(JSString, length));
 
         LIns* masked_len_ins = lir->ins2(LIR_piand,
                                          len_ins,
                                          INS_CONSTPTR(JSSTRING_LENGTH_MASK));
 
         LIns *choose_len_ins =