From 49b3d9bb1ac7aafdb4e9a1f9b6b68bee40c0cdfc Mon Sep 17 00:00:00 2001 From: Sankha Narayan Guria Date: Fri, 4 Jul 2014 13:54:34 +0200 Subject: [PATCH] Bug 989348 - BaselineCompiler: Optimize JSOP_ARRAYPUSH. r=djvj --- js/src/jit/BaselineCompiler.cpp | 30 +++++++---- js/src/jit/BaselineIC.cpp | 96 +++++++++++++++++++++++++++++++++ js/src/jit/BaselineIC.h | 66 +++++++++++++++++++++++ 3 files changed, 183 insertions(+), 9 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 5d2c9ba3732..f8de616976f 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1790,22 +1790,34 @@ BaselineCompiler::emit_JSOP_ENDINIT() return true; } -typedef bool (*NewbornArrayPushFn)(JSContext *, HandleObject, const Value &); -static const VMFunction NewbornArrayPushInfo = FunctionInfo(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 diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ac33e784965..1f7c5cafd95 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -9655,6 +9655,102 @@ ICTableSwitch::fixupJumpTable(JSScript *script, BaselineScript *baseline) 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 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(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 // diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 52d55e5eeb4..525d7219296 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -377,6 +377,9 @@ class ICEntry _(Call_ScriptedApplyArguments) \ _(Call_ScriptedFunCall) \ \ + _(ArrayPush_Fallback) \ + _(ArrayPush_Native) \ + \ _(GetElem_Fallback) \ _(GetElem_NativeSlot) \ _(GetElem_NativePrototypeSlot) \ @@ -2899,6 +2902,69 @@ class ICUnaryArith_Double : public ICStub }; }; +// 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(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(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