Bug 989348 - BaselineCompiler: Optimize JSOP_ARRAYPUSH. r=djvj
☠☠ backed out by f215d413b489 ☠ ☠
authorSankha Narayan Guria <sankha93@gmail.com>
Fri, 04 Jul 2014 13:54:34 +0200
changeset 215893 72d92f058cf0b146c30ed042a4ecfaff4cde9b22
parent 215892 b97d424843659357e4cf34e202229baadb481257
child 215894 51b6fd0998d81dcd0e9b1fe0e41e75375d451ba5
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs989348
milestone33.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 989348 - BaselineCompiler: Optimize JSOP_ARRAYPUSH. r=djvj
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1785,32 +1785,44 @@ BaselineCompiler::emit_JSOP_INITPROP()
 }
 
 bool
 BaselineCompiler::emit_JSOP_ENDINIT()
 {
     return true;
 }
 
-typedef bool (*NewbornArrayPushFn)(JSContext *, HandleObject, const Value &);
-static const VMFunction NewbornArrayPushInfo = FunctionInfo<NewbornArrayPushFn>(NewbornArrayPush);
-
 bool
 BaselineCompiler::emit_JSOP_ARRAYPUSH()
 {
     // Keep value in R0, object in R1.
     frame.popRegsAndSync(2);
+    #ifdef DEBUG
+    {
+        Label fail;
+        Label ok;
+        // Stub register is unused in mainline code, so we can use it as
+        // scratch
+        Register scratchReg = BaselineStubReg;
+        masm.branchTestObject(Assembler::NotEqual, R1, &fail);
+        Register objReg = masm.extractObject(R1, ExtractTemp0);
+        masm.branchTestObjClass(Assembler::Equal, objReg, scratchReg, &ArrayObject::class_, &ok);
+
+        masm.bind(&fail);
+        masm.assumeUnreachable("JSOP_ARRAYPUSH operand 1 is not an array.");
+
+        masm.bind(&ok);
+    }
+    #endif
+    // R1 is guaranteed to be a boxed Array object
     masm.unboxObject(R1, R1.scratchReg());
 
-    prepareVMCall();
-
-    pushArg(R0);
-    pushArg(R1.scratchReg());
-
-    return callVM(NewbornArrayPushInfo);
+    // Call IC.
+    ICArrayPush_Fallback::Compiler stubCompiler(cx);
+    return emitOpIC(stubCompiler.getStub(&stubSpace_));
 }
 
 bool
 BaselineCompiler::emit_JSOP_GETELEM()
 {
     // Keep top two stack values in R0 and R1.
     frame.popRegsAndSync(2);
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9651,16 +9651,112 @@ ICTableSwitch::fixupJumpTable(JSScript *
 {
     defaultTarget_ = baseline->nativeCodeForPC(script, (jsbytecode *) defaultTarget_);
 
     for (int32_t i = 0; i < length_; i++)
         table_[i] = baseline->nativeCodeForPC(script, (jsbytecode *) table_[i]);
 }
 
 //
+// ArrayPush_Fallback
+//
+static bool
+DoArrayPushFallback(JSContext *cx, BaselineFrame *frame, ICArrayPush_Fallback *stub_,
+                    HandleObject obj, HandleValue v)
+{
+    // This fallback stub may trigger debug mode toggling.
+    DebugModeOSRVolatileStub<ICArrayPush_Fallback *> stub(frame, stub_);
+
+    FallbackICSpew(cx, stub, "ArrayPush");
+
+    if (!NewbornArrayPush(cx, obj, v))
+        return false;
+
+    // Check if debug mode toggling made the stub invalid.
+    if (stub.invalid())
+        return true;
+
+    if (!stub->hasStub(ICStub::ArrayPush_Native))
+    {
+        ICArrayPush_Native::Compiler compiler(cx);
+        ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
+        if (!newStub)
+            return false;
+        stub->addNewStub(newStub);
+    }
+
+    return true;
+}
+
+typedef bool (*DoArrayPushFallbackFn)(JSContext *, BaselineFrame *, ICArrayPush_Fallback *,
+              HandleObject, HandleValue);
+static const VMFunction DoArrayPushFallbackInfo = FunctionInfo<DoArrayPushFallbackFn>(DoArrayPushFallback);
+
+bool
+ICArrayPush_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
+{
+    // Restore the tail call register.
+    EmitRestoreTailCallReg(masm);
+
+    // Push arguments.
+    masm.pushValue(R0);
+    masm.push(R1.scratchReg());
+    masm.push(BaselineStubReg);
+    masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
+
+    return tailCallVM(DoArrayPushFallbackInfo, masm);
+}
+
+//
+// ArrayPush_Native
+//
+
+bool
+ICArrayPush_Native::Compiler::generateStubCode(MacroAssembler &masm)
+{
+    Label failure;
+
+    Register obj = R1.scratchReg();
+    GeneralRegisterSet regs(availableGeneralRegs(1));
+    regs.take(obj);
+    Register elementsTemp = regs.takeAny();
+    Register length = regs.takeAny();
+
+    masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
+    masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
+    #ifdef DEBUG
+    {
+      Label ok;
+      masm.branch32(Assembler::Equal,
+                    Address(elementsTemp,
+                            ObjectElements::offsetOfInitializedLength()),
+                    length,
+                    &ok);
+      masm.assumeUnreachable("ArrayPush array length != initializedLength");
+      masm.bind(&ok);
+    }
+    #endif
+    masm.branch32(Assembler::BelowOrEqual,
+                  Address(elementsTemp, ObjectElements::offsetOfCapacity()),
+                  length, &failure);
+    Int32Key key = Int32Key(length);
+
+    JS_STATIC_ASSERT(sizeof(Value) == 8);
+    masm.storeValue(R0, BaseIndex(elementsTemp, length, TimesEight));
+    masm.bumpKey(&key, 1);
+    masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
+    masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
+    EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+//
 // IteratorNew_Fallback
 //
 
 static bool
 DoIteratorNewFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNew_Fallback *stub,
                       HandleValue value, MutableHandleValue res)
 {
     jsbytecode *pc = stub->icEntry()->pc(frame->script());
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -372,16 +372,19 @@ class ICEntry
     _(Call_Fallback)            \
     _(Call_Scripted)            \
     _(Call_AnyScripted)         \
     _(Call_Native)              \
     _(Call_ScriptedApplyArray)  \
     _(Call_ScriptedApplyArguments) \
     _(Call_ScriptedFunCall)     \
                                 \
+    _(ArrayPush_Fallback)       \
+    _(ArrayPush_Native)         \
+                                \
     _(GetElem_Fallback)         \
     _(GetElem_NativeSlot)       \
     _(GetElem_NativePrototypeSlot) \
     _(GetElem_NativePrototypeCallNative) \
     _(GetElem_NativePrototypeCallScripted) \
     _(GetElem_String)           \
     _(GetElem_Dense)            \
     _(GetElem_TypedArray)       \
@@ -2894,16 +2897,79 @@ class ICUnaryArith_Double : public ICStu
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICUnaryArith_Double::New(space, getStubCode());
         }
     };
 };
 
+// ArrayPush
+//      JSOP_ARRAYPUSH
+
+class ICArrayPush_Fallback : public ICFallbackStub
+{
+    friend class ICStubSpace;
+
+    explicit ICArrayPush_Fallback(JitCode *stubCode)
+      : ICFallbackStub(ArrayPush_Fallback, stubCode)
+    {}
+
+  public:
+    static inline ICArrayPush_Fallback *New(ICStubSpace *space, JitCode *code) {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICArrayPush_Fallback>(code);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        bool generateStubCode(MacroAssembler &masm);
+
+      public:
+        Compiler(JSContext *cx)
+          : ICStubCompiler(cx, ICStub::ArrayPush_Fallback)
+        {}
+
+        ICStub *getStub(ICStubSpace *space) {
+            return ICArrayPush_Fallback::New(space, getStubCode());
+        }
+    };
+};
+
+class ICArrayPush_Native : public ICStub
+{
+    friend class ICStubSpace;
+
+    explicit ICArrayPush_Native(JitCode *stubCode)
+      : ICStub(ArrayPush_Native, stubCode)
+    {}
+
+  public:
+    static inline ICArrayPush_Native *New(ICStubSpace *space, JitCode *code) {
+        if (!code)
+            return nullptr;
+        return space->allocate<ICArrayPush_Native>(code);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        bool generateStubCode(MacroAssembler &masm);
+
+      public:
+        Compiler(JSContext *cx)
+          : ICStubCompiler(cx, ICStub::ArrayPush_Native)
+        {}
+
+        ICStub *getStub(ICStubSpace *space) {
+            return ICArrayPush_Native::New(space, getStubCode());
+        }
+    };
+};
+
 // GetElem
 //      JSOP_GETELEM
 
 class ICGetElem_Fallback : public ICMonitoredFallbackStub
 {
     friend class ICStubSpace;
 
     explicit ICGetElem_Fallback(JitCode *stubCode)