Bug 952944 - Refactor JSOP_ARRAYPUSH. r=jorendorff
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 18 Jan 2014 13:55:56 +0100
changeset 164138 56f89ea332f75e67657fbadf81d1370a31f68267
parent 164137 103c0b6c135d5b0ad65d018b2054165bae2a9532
child 164139 cc0ba35ea087eaf6acef269938210961f3134256
push id26026
push userphilringnalda@gmail.com
push dateSat, 18 Jan 2014 23:17:27 +0000
treeherdermozilla-central@61fd0f987cf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs952944
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952944 - Refactor JSOP_ARRAYPUSH. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsopcode.tbl
js/src/jsweakmap.cpp
js/src/vm/Debugger.cpp
js/src/vm/Interpreter.cpp
js/src/vm/Xdr.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6511,17 +6511,19 @@ frontend::EmitTree(ExclusiveContext *cx,
          * special casing. Note that the array object is a pure stack value,
          * unaliased by blocks, so we can EmitUnaliasedVarOp.
          */
         if (!EmitTree(cx, bce, pn->pn_kid))
             return false;
         uint32_t slot = bce->arrayCompDepth;
         if (!AdjustBlockSlot(cx, bce, &slot))
             return false;
-        if (!EmitUnaliasedVarOp(cx, pn->getOp(), slot, bce))
+        if (!EmitUnaliasedVarOp(cx, JSOP_GETLOCAL, slot, bce))
+            return false;
+        if (Emit1(cx, bce, JSOP_ARRAYPUSH) < 0)
             return false;
         break;
       }
 
       case PNK_ARRAY:
         if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
             ok = EmitSingletonInitialiser(cx, bce, pn);
         else
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1999,18 +1999,18 @@ js::array_sort(JSContext *cx, unsigned a
     while (len > n) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeletePropertyOrThrow(cx, obj, --len))
             return false;
     }
     args.rval().setObject(*obj);
     return true;
 }
 
-static JS_ALWAYS_INLINE bool
-NewbornArrayPushImpl(JSContext *cx, HandleObject obj, const Value &v)
+bool
+js::NewbornArrayPush(JSContext *cx, HandleObject obj, const Value &v)
 {
     Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
 
     JS_ASSERT(!v.isMagic());
     JS_ASSERT(arr->lengthIsWritable());
 
     uint32_t length = arr->length();
     JS_ASSERT(length <= arr->getDenseCapacity());
@@ -2019,22 +2019,16 @@ NewbornArrayPushImpl(JSContext *cx, Hand
         return false;
 
     arr->setDenseInitializedLength(length + 1);
     arr->setLengthInt32(length + 1);
     arr->initDenseElementWithType(cx, length, v);
     return true;
 }
 
-bool
-js_NewbornArrayPush(JSContext *cx, HandleObject obj, const Value &vp)
-{
-    return NewbornArrayPushImpl(cx, obj, vp);
-}
-
 /* ES5 15.4.4.7 */
 bool
 js::array_push(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -135,30 +135,30 @@ array_concat_dense(JSContext *cx, Handle
                    Handle<ArrayObject*> result);
 
 extern void
 ArrayShiftMoveElements(JSObject *obj);
 
 extern bool
 array_shift(JSContext *cx, unsigned argc, js::Value *vp);
 
-} /* namespace js */
-
-#ifdef DEBUG
-extern bool
-js_ArrayInfo(JSContext *cx, unsigned argc, js::Value *vp);
-#endif
-
 /*
  * Append the given (non-hole) value to the end of an array.  The array must be
  * a newborn array -- that is, one which has not been exposed to script for
  * arbitrary manipulation.  (This method optimizes on the assumption that
  * extending the array to accommodate the element will never make the array
  * sparse, which requires that the array be completely filled.)
  */
 extern bool
-js_NewbornArrayPush(JSContext *cx, js::HandleObject obj, const js::Value &v);
+NewbornArrayPush(JSContext *cx, HandleObject obj, const Value &v);
+
+} /* namespace js */
+
+#ifdef DEBUG
+extern bool
+js_ArrayInfo(JSContext *cx, unsigned argc, js::Value *vp);
+#endif
 
 /* Array constructor native. Exposed only so the JIT can know its address. */
 bool
 js_Array(JSContext *cx, unsigned argc, js::Value *vp);
 
 #endif /* jsarray_h */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -434,17 +434,17 @@ OPDEF(JSOP_DEBUGLEAVEBLOCK, 200,"debugle
 
 OPDEF(JSOP_UNUSED201,     201,"unused201",  NULL,     1,  0,  0,  JOF_BYTE)
 
 /*
  * Generator and array comprehension support.
  */
 OPDEF(JSOP_GENERATOR,     202,"generator",   NULL,    1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_YIELD,         203,"yield",       NULL,    1,  1,  1,  JOF_BYTE)
-OPDEF(JSOP_ARRAYPUSH,     204,"arraypush",   NULL,    4,  1,  0,  JOF_LOCAL)
+OPDEF(JSOP_ARRAYPUSH,     204,"arraypush",   NULL,    1,  2,  0,  JOF_BYTE)
 
 OPDEF(JSOP_UNUSED205,     205, "unused205",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED206,     206, "unused206",    NULL,  1,  0,  0,  JOF_BYTE)
 
 OPDEF(JSOP_UNUSED207,     207, "unused207",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED208,     208, "unused208",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE)
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -364,17 +364,17 @@ JS_NondeterministicGetWeakMapKeys(JSCont
     ObjectValueMap *map = obj->as<WeakMapObject>().getMap();
     if (map) {
         // Prevent GC from mutating the weakmap while iterating.
         gc::AutoSuppressGC suppress(cx);
         for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
             RootedObject key(cx, r.front().key());
             if (!cx->compartment()->wrap(cx, &key))
                 return false;
-            if (!js_NewbornArrayPush(cx, arr, ObjectValue(*key)))
+            if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
                 return false;
         }
     }
     *ret = arr;
     return true;
 }
 
 static void
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2732,17 +2732,17 @@ Debugger::findAllGlobals(JSContext *cx, 
              * marked gray by XPConnect. Since we're now exposing it to JS code,
              * we need to mark it black.
              */
             JS::ExposeGCThingToActiveJS(global, JSTRACE_OBJECT);
 
             RootedValue globalValue(cx, ObjectValue(*global));
             if (!dbg->wrapDebuggeeValue(cx, &globalValue))
                 return false;
-            if (!js_NewbornArrayPush(cx, result, globalValue))
+            if (!NewbornArrayPush(cx, result, globalValue))
                 return false;
         }
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
@@ -3023,17 +3023,17 @@ DebuggerScript_getChildScripts(JSContext
         for (uint32_t i = script->innerObjectsStart(); i < objects->length; i++) {
             obj = objects->vector[i];
             if (obj->is<JSFunction>()) {
                 fun = &obj->as<JSFunction>();
                 funScript = GetOrCreateFunctionScript(cx, fun);
                 if (!funScript)
                     return false;
                 s = dbg->wrapScript(cx, funScript);
-                if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
+                if (!s || !NewbornArrayPush(cx, result, ObjectValue(*s)))
                     return false;
             }
         }
     }
     args.rval().setObject(*result);
     return true;
 }
 
@@ -3355,17 +3355,17 @@ DebuggerScript_getAllOffsets(JSContext *
                 }
 
                 RootedValue value(cx, ObjectValue(*offsets));
                 if (!JSObject::defineGeneric(cx, result, id, value))
                     return false;
             }
 
             /* Append the current offset to the offsets array. */
-            if (!js_NewbornArrayPush(cx, offsets, NumberValue(offset)))
+            if (!NewbornArrayPush(cx, offsets, NumberValue(offset)))
                 return false;
         }
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
@@ -3408,17 +3408,17 @@ DebuggerScript_getAllColumnOffsets(JSCon
             if (!JSObject::defineProperty(cx, entry, cx->names().columnNumber, value))
                 return false;
 
             id = NameToId(cx->names().offset);
             value = NumberValue(offset);
             if (!JSObject::defineGeneric(cx, entry, id, value))
                 return false;
 
-            if (!js_NewbornArrayPush(cx, result, ObjectValue(*entry)))
+            if (!NewbornArrayPush(cx, result, ObjectValue(*entry)))
                 return false;
         }
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
@@ -3457,17 +3457,17 @@ DebuggerScript_getLineOffsets(JSContext 
     for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
         size_t offset = r.frontOffset();
 
         /* If the op at offset is an entry point, append offset to result. */
         if (r.frontLineNumber() == lineno &&
             !flowData[offset].hasNoEdges() &&
             flowData[offset].lineno() != lineno)
         {
-            if (!js_NewbornArrayPush(cx, result, NumberValue(offset)))
+            if (!NewbornArrayPush(cx, result, NumberValue(offset)))
                 return false;
         }
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
@@ -3570,17 +3570,17 @@ DebuggerScript_getBreakpoints(JSContext 
     if (!arr)
         return false;
 
     for (unsigned i = 0; i < script->length(); i++) {
         BreakpointSite *site = script->getBreakpointSite(script->offsetToPC(i));
         if (site && (!pc || site->pc == pc)) {
             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = bp->nextInSite()) {
                 if (bp->debugger == dbg &&
-                    !js_NewbornArrayPush(cx, arr, ObjectValue(*bp->getHandler())))
+                    !NewbornArrayPush(cx, arr, ObjectValue(*bp->getHandler())))
                 {
                     return false;
                 }
             }
         }
     }
     args.rval().setObject(*arr);
     return true;
@@ -5644,17 +5644,17 @@ DebuggerEnv_names(JSContext *cx, unsigne
     if (!arr)
         return false;
     RootedId id(cx);
     for (size_t i = 0, len = keys.length(); i < len; i++) {
         id = keys[i];
         if (JSID_IS_ATOM(id) && IsIdentifier(JSID_TO_ATOM(id))) {
             if (!cx->compartment()->wrapId(cx, id.address()))
                 return false;
-            if (!js_NewbornArrayPush(cx, arr, StringValue(JSID_TO_STRING(id))))
+            if (!NewbornArrayPush(cx, arr, StringValue(JSID_TO_STRING(id))))
                 return false;
         }
     }
     args.rval().setObject(*arr);
     return true;
 }
 
 static bool
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3390,24 +3390,21 @@ CASE(JSOP_YIELD)
     REGS.fp()->setReturnValue(REGS.sp[-1]);
     REGS.fp()->setYielding();
     REGS.pc += JSOP_YIELD_LENGTH;
     interpReturnOK = true;
     goto exit;
 
 CASE(JSOP_ARRAYPUSH)
 {
-    uint32_t slot = GET_LOCALNO(REGS.pc);
-    JS_ASSERT(script->nfixed() <= slot);
-    JS_ASSERT(slot < script->nslots());
     RootedObject &obj = rootObject0;
-    obj = &REGS.fp()->unaliasedLocal(slot).toObject();
-    if (!js_NewbornArrayPush(cx, obj, REGS.sp[-1]))
+    obj = &REGS.sp[-1].toObject();
+    if (!NewbornArrayPush(cx, obj, REGS.sp[-2]))
         goto error;
-    REGS.sp--;
+    REGS.sp -= 2;
 }
 END_CASE(JSOP_ARRAYPUSH)
 
 DEFAULT()
 {
     char numBuf[12];
     JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc);
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -17,17 +17,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 162);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 163);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;