Bug 1501865: Migrate IsSuspendedGenerator to CacheIR r=mgaudet
authorIain Ireland <iireland@mozilla.com>
Tue, 27 Nov 2018 18:35:27 +0000
changeset 507745 6c8636acf2cd7b775380d18cce1542a8117a3bc0
parent 507744 a823c2262dbf17325c965a6fdc66f0366de2e249
child 507746 74d97073c54b19e742b084ea9f03b7ba40233000
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmgaudet
bugs1501865
milestone65.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 1501865: Migrate IsSuspendedGenerator to CacheIR r=mgaudet Differential Revision: https://phabricator.services.mozilla.com/D12960
js/src/jit/BaselineCacheIRCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineICList.h
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -2164,23 +2164,26 @@ BaselineCacheIRCompiler::init(CacheKind 
         allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_OBJECT);
 #if defined(JS_NUNBOX32)
         // availableGeneralRegs can't know that GetName/BindName is only using
         // the payloadReg and not typeReg on x86.
         available.add(R0.typeReg());
 #endif
         break;
       case CacheKind::Call:
-        MOZ_ASSERT(numInputs == 1);
-        allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_INT32);
+        // Calls pass argc in R0. CallICs may or may not use it.
+        MOZ_ASSERT(numInputs == 0 || numInputs == 1);
+        if (numInputs == 1) {
+            allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_INT32);
 #if defined(JS_NUNBOX32)
-        // availableGeneralRegs can't know that Call is only using
-        // the payloadReg and not typeReg on x86.
-        available.add(R0.typeReg());
+            // availableGeneralRegs can't know that Call is only using
+            // the payloadReg and not typeReg on x86.
+            available.add(R0.typeReg());
 #endif
+        }
         break;
     }
 
     // Baseline doesn't allocate float registers so none of them are live.
     liveFloatRegs_ = LiveFloatRegisterSet(FloatRegisterSet());
 
     allocator.initAvailableRegs(available);
     outputUnchecked_.emplace(R0);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3444,33 +3444,16 @@ TryAttachCallStub(JSContext* cx, ICCall_
         }
 
         if (stub->state().mode() == ICState::Mode::Megamorphic) {
             JitSpew(JitSpew_BaselineIC,
                     "  Megamorphic Call_Native stubs. TODO: add Call_AnyNative!");
             return true;
         }
 
-        if (fun->native() == intrinsic_IsSuspendedGenerator) {
-            // This intrinsic only appears in self-hosted code.
-            MOZ_ASSERT(op != JSOP_NEW);
-            MOZ_ASSERT(argc == 1);
-            JitSpew(JitSpew_BaselineIC, "  Generating Call_IsSuspendedGenerator stub");
-
-            ICCall_IsSuspendedGenerator::Compiler compiler(cx);
-            ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-            if (!newStub) {
-                return false;
-            }
-
-            stub->addNewStub(newStub);
-            *handled = true;
-            return true;
-        }
-
         bool isCrossRealm = cx->realm() != fun->realm();
 
         RootedObject templateObject(cx);
         if (MOZ_LIKELY(!isSpread && !isSuper && !isCrossRealm)) {
             bool skipAttach = false;
             CallArgs args = CallArgsFromVp(argc, vp);
             if (!GetTemplateObjectForNative(cx, fun, args, &templateObject, &skipAttach)) {
                 return false;
@@ -4593,59 +4576,16 @@ ICCall_ConstStringSplit::Compiler::gener
     // Guard failure path.
     masm.bind(&failureRestoreArgc);
     masm.move32(Imm32(2), R0.scratchReg());
     EmitStubGuardFailure(masm);
     return true;
 }
 
 bool
-ICCall_IsSuspendedGenerator::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    // The IsSuspendedGenerator intrinsic is only called in self-hosted code,
-    // so it's safe to assume we have a single argument and the callee is our
-    // intrinsic.
-
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
-
-    // Load the argument.
-    Address argAddr(masm.getStackPointer(), ICStackValueOffset);
-    ValueOperand argVal = regs.takeAnyValue();
-    masm.loadValue(argAddr, argVal);
-
-    // Check if it's an object.
-    Label returnFalse;
-    Register genObj = regs.takeAny();
-    masm.branchTestObject(Assembler::NotEqual, argVal, &returnFalse);
-    masm.unboxObject(argVal, genObj);
-
-    // Check if it's a GeneratorObject.
-    Register scratch = regs.takeAny();
-    masm.branchTestObjClass(Assembler::NotEqual, genObj, &GeneratorObject::class_, scratch,
-                            genObj, &returnFalse);
-
-    // If the resumeIndex slot holds an int32 value < RESUME_INDEX_CLOSING,
-    // the generator is suspended.
-    masm.loadValue(Address(genObj, GeneratorObject::offsetOfResumeIndexSlot()), argVal);
-    masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
-    masm.unboxInt32(argVal, scratch);
-    masm.branch32(Assembler::AboveOrEqual, scratch,
-                  Imm32(GeneratorObject::RESUME_INDEX_CLOSING),
-                  &returnFalse);
-
-    masm.moveValue(BooleanValue(true), R0);
-    EmitReturnFromIC(masm);
-
-    masm.bind(&returnFalse);
-    masm.moveValue(BooleanValue(false), R0);
-    EmitReturnFromIC(masm);
-    return true;
-}
-
-bool
 ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
 {
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     Register argcReg = R0.scratchReg();
     regs.take(argcReg);
     regs.takeUnchecked(ICTailCallReg);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -2567,40 +2567,16 @@ class ICCall_ConstStringSplit : public I
         ICStub* getStub(ICStubSpace* space) override {
             return newStub<ICCall_ConstStringSplit>(space, getStubCode(), firstMonitorStub_,
                                                     pcOffset_, expectedStr_, expectedSep_,
                                                     templateObject_);
         }
    };
 };
 
-class ICCall_IsSuspendedGenerator : public ICStub
-{
-    friend class ICStubSpace;
-
-  protected:
-    explicit ICCall_IsSuspendedGenerator(JitCode* stubCode)
-      : ICStub(ICStub::Call_IsSuspendedGenerator, stubCode)
-    {}
-
-  public:
-    class Compiler : public ICStubCompiler {
-      protected:
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        explicit Compiler(JSContext* cx)
-          : ICStubCompiler(cx, ICStub::Call_IsSuspendedGenerator)
-        {}
-        ICStub* getStub(ICStubSpace* space) override {
-            return newStub<ICCall_IsSuspendedGenerator>(space, getStubCode());
-        }
-   };
-};
-
 // IC for constructing an iterator from an input value.
 class ICGetIterator_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     explicit ICGetIterator_Fallback(JitCode* stubCode)
       : ICFallbackStub(ICStub::GetIterator_Fallback, stubCode)
     { }
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -40,17 +40,16 @@ namespace jit {
     _(Call_Scripted)                             \
     _(Call_AnyScripted)                          \
     _(Call_Native)                               \
     _(Call_ClassHook)                            \
     _(Call_ScriptedApplyArray)                   \
     _(Call_ScriptedApplyArguments)               \
     _(Call_ScriptedFunCall)                      \
     _(Call_ConstStringSplit)                     \
-    _(Call_IsSuspendedGenerator)                 \
                                                  \
     _(GetElem_Fallback)                          \
     _(SetElem_Fallback)                          \
                                                  \
     _(In_Fallback)                               \
     _(HasOwn_Fallback)                           \
                                                  \
     _(GetName_Fallback)                          \
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -5207,16 +5207,47 @@ CallIRGenerator::tryAttachArrayJoin()
     // Set the stub kind to Regular
     cacheIRStubKind_ = BaselineCacheIRStubKind::Regular;
 
     trackAttached("ArrayJoin");
     return true;
 }
 
 bool
+CallIRGenerator::tryAttachIsSuspendedGenerator()
+{
+    // The IsSuspendedGenerator intrinsic is only called in
+    // self-hosted code, so it's safe to assume we have a single
+    // argument and the callee is our intrinsic.
+
+    MOZ_ASSERT(argc_ == 1);
+
+    // Stack layout here is (bottom to top):
+    //  2: Callee
+    //  1: ThisValue
+    //  0: Arg <-- Top of stack.
+    // We only care about the argument.
+    ValOperandId valId = writer.loadStackValue(0);
+
+    // Check whether the argument is a suspended generator.
+    // We don't need guards, because IsSuspendedGenerator returns
+    // false for values that are not generator objects.
+    writer.callIsSuspendedGeneratorResult(valId);
+    writer.returnFromIC();
+
+    // This stub does not need to be monitored, because it always
+    // returns Boolean. The stack typeset will be updated when we
+    // attach the stub.
+    cacheIRStubKind_ = BaselineCacheIRStubKind::Regular;
+
+    trackAttached("IsSuspendedGenerator");
+    return true;
+}
+
+bool
 CallIRGenerator::tryAttachStub()
 {
     AutoAssertNoPendingException aanpe(cx_);
 
     // Only optimize on JSOP_CALL or JSOP_CALL_IGNORES_RV.  No fancy business for now.
     if ((op_ != JSOP_CALL) && (op_ != JSOP_CALL_IGNORES_RV)) {
         return false;
     }
@@ -5247,16 +5278,21 @@ CallIRGenerator::tryAttachStub()
             }
         }
 
         if (calleeFunc->native() == js::array_join) {
             if (tryAttachArrayJoin()) {
                 return true;
             }
         }
+        if (calleeFunc->native() == intrinsic_IsSuspendedGenerator) {
+            if (tryAttachIsSuspendedGenerator()) {
+                return true;
+            }
+        }
     }
 
     return false;
 }
 
 void
 CallIRGenerator::trackAttached(const char* name)
 {
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -335,16 +335,17 @@ extern const char* const CacheKindNames[
     _(LoadStringTruthyResult)             \
     _(LoadObjectTruthyResult)             \
     _(LoadValueResult)                    \
     _(LoadNewObjectFromTemplateResult)    \
                                           \
     _(CallStringSplitResult)              \
     _(CallStringConcatResult)             \
     _(CallStringObjectConcatResult)       \
+    _(CallIsSuspendedGeneratorResult)     \
                                           \
     _(CompareStringResult)                \
     _(CompareObjectResult)                \
     _(CompareSymbolResult)                \
     _(CompareInt32Result)                 \
     _(CompareDoubleResult)                \
     _(CompareObjectUndefinedNullResult)   \
                                           \
@@ -1295,16 +1296,19 @@ class MOZ_RAII CacheIRWriter : public JS
     void callObjectHasSparseElementResult(ObjOperandId obj, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::CallObjectHasSparseElementResult, obj);
         writeOperandId(index);
     }
     void callNativeGetElementResult(ObjOperandId obj, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::CallNativeGetElementResult, obj);
         writeOperandId(index);
     }
+    void callIsSuspendedGeneratorResult(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::CallIsSuspendedGeneratorResult, val);
+    }
     void loadEnvironmentFixedSlotResult(ObjOperandId obj, size_t offset) {
         writeOpWithOperandId(CacheOp::LoadEnvironmentFixedSlotResult, obj);
         addStubField(offset, StubField::Type::RawWord);
     }
     void loadEnvironmentDynamicSlotResult(ObjOperandId obj, size_t offset) {
         writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
         addStubField(offset, StubField::Type::RawWord);
     }
@@ -1922,16 +1926,17 @@ class MOZ_RAII CallIRGenerator : public 
     HandleValue thisval_;
     HandleValueArray args_;
     PropertyTypeCheckInfo typeCheckInfo_;
     BaselineCacheIRStubKind cacheIRStubKind_;
 
     bool tryAttachStringSplit();
     bool tryAttachArrayPush();
     bool tryAttachArrayJoin();
+    bool tryAttachIsSuspendedGenerator();
 
     void trackAttached(const char* name);
 
   public:
     CallIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
                     JSOp op, ICState::Mode mode,
                     uint32_t argc, HandleValue callee, HandleValue thisval,
                     HandleValueArray args);
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/ScopeExit.h"
 
 #include <utility>
 
 #include "jslibmath.h"
 #include "jit/IonIC.h"
 #include "jit/SharedICHelpers.h"
 #include "jit/SharedICRegisters.h"
+#include "vm/GeneratorObject.h"
 
 #include "builtin/Boolean-inl.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/Realm-inl.h"
 
 using namespace js;
 using namespace js::jit;
@@ -4263,8 +4264,44 @@ js::jit::LoadTypedThingLength(MacroAssem
       case Layout_OutlineTypedObject:
       case Layout_InlineTypedObject:
         masm.loadTypedObjectLength(obj, result);
         break;
       default:
         MOZ_CRASH();
     }
 }
+
+bool
+CacheIRCompiler::emitCallIsSuspendedGeneratorResult()
+{
+    AutoOutputRegister output(*this);
+    AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
+    AutoScratchRegister scratch2(allocator, masm);
+    ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
+
+    // Test if it's an object.
+    Label returnFalse, done;
+    masm.branchTestObject(Assembler::NotEqual, input, &returnFalse);
+
+    // Test if it's a GeneratorObject.
+    masm.unboxObject(input, scratch);
+    masm.branchTestObjClass(Assembler::NotEqual, scratch, &GeneratorObject::class_,
+                            scratch2, scratch, &returnFalse);
+
+    // If the resumeIndex slot holds an int32 value < RESUME_INDEX_CLOSING,
+    // the generator is suspended.
+    Address addr(scratch, GeneratorObject::offsetOfResumeIndexSlot());
+    masm.branchTestInt32(Assembler::NotEqual, addr, &returnFalse);
+    masm.unboxInt32(addr, scratch);
+    masm.branch32(Assembler::AboveOrEqual, scratch,
+                  Imm32(GeneratorObject::RESUME_INDEX_CLOSING),
+                  &returnFalse);
+
+    masm.moveValue(BooleanValue(true), output.valueReg());
+    masm.jump(&done);
+
+    masm.bind(&returnFalse);
+    masm.moveValue(BooleanValue(false), output.valueReg());
+
+    masm.bind(&done);
+    return true;
+}
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -114,16 +114,17 @@ namespace jit {
     _(Breakpoint)                         \
     _(MegamorphicLoadSlotResult)          \
     _(MegamorphicLoadSlotByValueResult)   \
     _(MegamorphicStoreSlot)               \
     _(MegamorphicHasPropResult)           \
     _(CallObjectHasSparseElementResult)   \
     _(CallInt32ToString)                  \
     _(CallNumberToString)                 \
+    _(CallIsSuspendedGeneratorResult)     \
     _(WrapResult)
 
 
 // [SMDDOC] CacheIR Value Representation and Tracking
 //
 // While compiling an IC stub the CacheIR compiler needs to keep track of the
 // physical location for each logical piece of data we care about, as well as
 // ensure that in the case of a stub failing, we are able to restore the input