Bug 1320145 part 2 - Port length/callee stubs on lazy arguments to CacheIR. r=nbp
authorJan de Mooij <jdemooij@mozilla.com>
Sun, 04 Dec 2016 20:14:05 -1000
changeset 325281 2e0998e9e1d0d726872404e8775b5f3d817cf8f7
parent 325280 7a6b69786d1e56d4e954fba49ee94c2b17653e37
child 325282 d16912005e866e26f37ae7d6b27b00b91645f76b
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersnbp
bugs1320145
milestone53.0a1
Bug 1320145 part 2 - Port length/callee stubs on lazy arguments to CacheIR. r=nbp
js/src/jit/BaselineCacheIR.cpp
js/src/jit/BaselineInspector.cpp
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/SharedIC.cpp
js/src/jit/SharedIC.h
js/src/jit/SharedICList.h
--- a/js/src/jit/BaselineCacheIR.cpp
+++ b/js/src/jit/BaselineCacheIR.cpp
@@ -1087,16 +1087,30 @@ BaselineCacheIRCompiler::emitGuardSpecif
         return false;
 
     Address addr(stubAddress(reader.stubOffset()));
     masm.branchPtr(Assembler::NotEqual, addr, obj, failure->label());
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitGuardMagicValue()
+{
+    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
+    JSWhyMagic magic = reader.whyMagic();
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTestMagicValue(Assembler::NotEqual, val, magic, failure->label());
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitGuardNoUnboxedExpando()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
@@ -1292,16 +1306,48 @@ BaselineCacheIRCompiler::emitGuardNoDeta
     if (!addFailurePath(&failure))
         return false;
 
     CheckForTypedObjectWithDetachedStorage(cx_, masm, failure->label());
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitGuardFrameHasNoArgumentsObject()
+{
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTest32(Assembler::NonZero,
+                      Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
+                      Imm32(BaselineFrame::HAS_ARGS_OBJ),
+                      failure->label());
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitLoadFrameCalleeResult()
+{
+    Address callee(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
+    masm.loadFunctionFromCalleeToken(callee, R0.scratchReg());
+    masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitLoadFrameNumActualArgsResult()
+{
+    Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
+    masm.loadPtr(actualArgs, R0.scratchReg());
+    masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitLoadTypedObjectResult()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     AutoScratchRegister scratch1(allocator, masm);
     AutoScratchRegister scratch2(allocator, masm);
 
     TypedThingLayout layout = reader.typedThingLayout();
     uint32_t typeDescr = reader.typeDescrKey();
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1011,17 +1011,16 @@ BaselineInspector::expectedPropertyAcces
           case ICStub::GetElem_Fallback:
             if (stub->toGetElem_Fallback()->hadUnoptimizableAccess())
                 return MIRType::Value;
             continue;
 
           case ICStub::GetProp_Generic:
             return MIRType::Value;
 
-          case ICStub::GetProp_ArgumentsLength:
           case ICStub::GetElem_Arguments:
             // Either an object or magic arguments.
             return MIRType::Value;
 
           case ICStub::GetElem_NativeSlotName:
           case ICStub::GetElem_NativeSlotSymbol:
           case ICStub::GetElem_NativePrototypeSlotName:
           case ICStub::GetElem_NativePrototypeSlotSymbol:
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -74,16 +74,18 @@ GetPropIRGenerator::tryAttachStub()
             return true;
         return false;
     }
 
     if (tryAttachPrimitive(valId))
         return true;
     if (tryAttachStringLength(valId))
         return true;
+    if (tryAttachMagicArguments(valId))
+        return true;
 
     return false;
 }
 
 static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
                       jsbytecode* pc)
 {
@@ -732,8 +734,32 @@ GetPropIRGenerator::tryAttachStringLengt
     if (!val_.isString() || name_ != cx_->names().length)
         return false;
 
     StringOperandId strId = writer.guardIsString(valId);
     writer.loadStringLengthResult(strId);
     writer.returnFromIC();
     return true;
 }
+
+bool
+GetPropIRGenerator::tryAttachMagicArguments(ValOperandId valId)
+{
+    if (!val_.isMagic(JS_OPTIMIZED_ARGUMENTS))
+        return false;
+
+    if (name_ != cx_->names().length && name_ != cx_->names().callee)
+        return false;
+
+    writer.guardMagicValue(valId, JS_OPTIMIZED_ARGUMENTS);
+    writer.guardFrameHasNoArgumentsObject();
+
+    if (name_ == cx_->names().length) {
+        writer.loadFrameNumActualArgsResult();
+        writer.returnFromIC();
+    } else {
+        MOZ_ASSERT(name_ == cx_->names().callee);
+        writer.loadFrameCalleeResult();
+        writer.typeMonitorResult();
+    }
+
+    return true;
+}
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -108,16 +108,18 @@ class TypedOperandId : public OperandId
     _(GuardShape)                         \
     _(GuardGroup)                         \
     _(GuardProto)                         \
     _(GuardClass)                         \
     _(GuardIsProxy)                       \
     _(GuardNotDOMProxy)                   \
     _(GuardSpecificObject)                \
     _(GuardNoDetachedTypedObjects)        \
+    _(GuardMagicValue)                    \
+    _(GuardFrameHasNoArgumentsObject)     \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(LoadObject)                         \
     _(LoadProto)                          \
                                           \
     _(LoadDOMExpandoValue)                \
     _(GuardDOMExpandoObject)              \
     _(GuardDOMExpandoGeneration)          \
@@ -126,16 +128,18 @@ class TypedOperandId : public OperandId
     _(LoadFixedSlotResult)                \
     _(LoadDynamicSlotResult)              \
     _(LoadUnboxedPropertyResult)          \
     _(LoadTypedObjectResult)              \
     _(LoadInt32ArrayLengthResult)         \
     _(LoadUnboxedArrayLengthResult)       \
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadStringLengthResult)             \
+    _(LoadFrameCalleeResult)              \
+    _(LoadFrameNumActualArgsResult)       \
     _(CallScriptedGetterResult)           \
     _(CallNativeGetterResult)             \
     _(CallProxyGetResult)                 \
     _(LoadUndefinedResult)                \
                                           \
     _(TypeMonitorResult)                  \
     _(ReturnFromIC)
 
@@ -366,19 +370,32 @@ class MOZ_RAII CacheIRWriter : public JS
     }
     void guardNotDOMProxy(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
     }
     void guardSpecificObject(ObjOperandId obj, JSObject* expected) {
         writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
         addStubField(uintptr_t(expected), StubField::Type::JSObject);
     }
+    void guardMagicValue(ValOperandId val, JSWhyMagic magic) {
+        writeOpWithOperandId(CacheOp::GuardMagicValue, val);
+        buffer_.writeByte(uint32_t(magic));
+    }
     void guardNoDetachedTypedObjects() {
         writeOp(CacheOp::GuardNoDetachedTypedObjects);
     }
+    void guardFrameHasNoArgumentsObject() {
+        writeOp(CacheOp::GuardFrameHasNoArgumentsObject);
+    }
+    void loadFrameCalleeResult() {
+        writeOp(CacheOp::LoadFrameCalleeResult);
+    }
+    void loadFrameNumActualArgsResult() {
+        writeOp(CacheOp::LoadFrameNumActualArgsResult);
+    }
     void guardNoUnboxedExpando(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
     }
     ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
         ObjOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
         writeOperandId(res);
         return res;
@@ -506,16 +523,17 @@ class MOZ_RAII CacheIRReader
     ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
     StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
 
     uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
     GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
     JSValueType valueType() { return JSValueType(buffer_.readByte()); }
     TypedThingLayout typedThingLayout() { return TypedThingLayout(buffer_.readByte()); }
     uint32_t typeDescrKey() { return buffer_.readByte(); }
+    JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
 
     bool matchOp(CacheOp op) {
         const uint8_t* pos = buffer_.currentPosition();
         if (readOp() == op)
             return true;
         buffer_.seek(pos, 0);
         return false;
     }
@@ -561,16 +579,17 @@ class MOZ_RAII GetPropIRGenerator
 
     bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId);
     bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId);
     bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId);
     bool tryAttachProxy(HandleObject obj, ObjOperandId objId);
 
     bool tryAttachPrimitive(ValOperandId valId);
     bool tryAttachStringLength(ValOperandId valId);
+    bool tryAttachMagicArguments(ValOperandId valId);
 
     GetPropIRGenerator(const GetPropIRGenerator&) = delete;
     GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
 
   public:
     GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
                        bool* isTemporarilyUnoptimizable,
                        HandleValue val, HandlePropertyName name, MutableHandleValue res);
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -2057,70 +2057,16 @@ ICCompare_Int32WithBoolean::Compiler::ge
     EmitStubGuardFailure(masm);
     return true;
 }
 
 //
 // GetProp_Fallback
 //
 
-static bool
-TryAttachMagicArgumentsGetPropStub(JSContext* cx, SharedStubInfo* info,
-                                   ICGetProp_Fallback* stub, HandlePropertyName name,
-                                   HandleValue val, HandleValue res, bool* attached)
-{
-    MOZ_ASSERT(!*attached);
-
-    if (!val.isMagic(JS_OPTIMIZED_ARGUMENTS))
-        return true;
-
-    // Try handling arguments.callee on optimized arguments.
-    if (name == cx->names().callee) {
-        MOZ_ASSERT(info->script()->hasMappedArgsObj());
-
-        JitSpew(JitSpew_BaselineIC, "  Generating GetProp(MagicArgs.callee) stub");
-
-        // Unlike ICGetProp_ArgumentsLength, only magic argument stubs are
-        // supported at the moment.
-        ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-        ICGetProp_ArgumentsCallee::Compiler compiler(cx, info->engine(), monitorStub);
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));
-        if (!newStub)
-            return false;
-        stub->addNewStub(newStub);
-
-        *attached = true;
-        return true;
-    }
-
-    return true;
-}
-
-static bool
-TryAttachLengthStub(JSContext* cx, SharedStubInfo* info,
-                    ICGetProp_Fallback* stub, HandleValue val,
-                    HandleValue res, bool* attached)
-{
-    MOZ_ASSERT(!*attached);
-
-    if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && res.isInt32()) {
-        JitSpew(JitSpew_BaselineIC, "  Generating GetProp(MagicArgs.length) stub");
-        ICGetProp_ArgumentsLength::Compiler compiler(cx, info->engine(), ICGetProp_ArgumentsLength::Magic);
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));
-        if (!newStub)
-            return false;
-
-        *attached = true;
-        stub->addNewStub(newStub);
-        return true;
-    }
-
-    return true;
-}
-
 // Return whether obj is in some PreliminaryObjectArray and has a structure
 // that might change in the future.
 bool
 IsPreliminaryObject(JSObject* obj)
 {
     if (obj->isSingleton())
         return false;
 
@@ -2484,30 +2430,16 @@ DoGetPropFallback(JSContext* cx, void* p
 
     // Add a type monitor stub for the resulting value.
     if (!stub->addMonitorStubForValue(cx, &info, res))
         return false;
 
     if (attached)
         return true;
 
-    if (op == JSOP_LENGTH) {
-        if (!TryAttachLengthStub(cx, &info, stub, val, res, &attached))
-            return false;
-        if (attached)
-            return true;
-    }
-
-    if (!TryAttachMagicArgumentsGetPropStub(cx, &info, stub, name, val,
-                                            res, &attached))
-        return false;
-    if (attached)
-        return true;
-
-
     MOZ_ASSERT(!attached);
     if (!isTemporarilyUnoptimizable)
         stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoGetPropFallbackFn)(JSContext*, void*, ICGetProp_Fallback*,
@@ -2840,71 +2772,16 @@ ICGetPropCallNativeCompiler::getStub(ICS
                                                    getter_, pcOffset_);
       }
 
       default:
         MOZ_CRASH("Bad stub kind");
     }
 }
 
-bool
-ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(which_ == ICGetProp_ArgumentsLength::Magic);
-
-    Label failure;
-
-    // Ensure that this is lazy arguments.
-    masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
-
-    // Ensure that frame has not loaded different arguments object since.
-    masm.branchTest32(Assembler::NonZero,
-                      Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
-                      Imm32(BaselineFrame::HAS_ARGS_OBJ),
-                      &failure);
-
-    Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
-    masm.loadPtr(actualArgs, R0.scratchReg());
-    masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
-    EmitReturnFromIC(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-ICGetProp_ArgumentsCallee::ICGetProp_ArgumentsCallee(JitCode* stubCode, ICStub* firstMonitorStub)
-  : ICMonitoredStub(GetProp_ArgumentsCallee, stubCode, firstMonitorStub)
-{ }
-
-bool
-ICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label failure;
-
-    // Ensure that this is lazy arguments.
-    masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
-
-    // Ensure that frame has not loaded different arguments object since.
-    masm.branchTest32(Assembler::NonZero,
-                      Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
-                      Imm32(BaselineFrame::HAS_ARGS_OBJ),
-                      &failure);
-
-    Address callee(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
-    masm.loadFunctionFromCalleeToken(callee, R0.scratchReg());
-    masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
-
-    EmitEnterTypeMonitorIC(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
 /* static */ ICGetProp_Generic*
 ICGetProp_Generic::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
                          ICGetProp_Generic& other)
 {
     return New<ICGetProp_Generic>(cx, space, other.jitCode(), firstMonitorStub);
 }
 
 static bool
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -2645,77 +2645,16 @@ class ICGetPropCallNativeCompiler : publ
       : ICGetPropCallGetter::Compiler(cx, kind, engine, firstMonitorStub, receiver, holder,
                                       getter, pcOffset),
         inputDefinitelyObject_(inputDefinitelyObject)
     {}
 
     ICStub* getStub(ICStubSpace* space);
 };
 
-class ICGetProp_ArgumentsLength : public ICStub
-{
-  friend class ICStubSpace;
-  public:
-    enum Which { Magic };
-
-  protected:
-    explicit ICGetProp_ArgumentsLength(JitCode* stubCode)
-      : ICStub(ICStub::GetProp_ArgumentsLength, stubCode)
-    { }
-
-  public:
-    class Compiler : public ICStubCompiler {
-      protected:
-        Which which_;
-
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
-        virtual int32_t getKey() const {
-            return static_cast<int32_t>(engine_) |
-                  (static_cast<int32_t>(kind) << 1) |
-                  (static_cast<int32_t>(which_) << 17);
-        }
-
-      public:
-        Compiler(JSContext* cx, Engine engine, Which which)
-          : ICStubCompiler(cx, ICStub::GetProp_ArgumentsLength, engine),
-            which_(which)
-        {}
-
-        ICStub* getStub(ICStubSpace* space) {
-            return newStub<ICGetProp_ArgumentsLength>(space, getStubCode());
-        }
-    };
-};
-
-class ICGetProp_ArgumentsCallee : public ICMonitoredStub
-{
-    friend class ICStubSpace;
-
-  protected:
-    ICGetProp_ArgumentsCallee(JitCode* stubCode, ICStub* firstMonitorStub);
-
-  public:
-    class Compiler : public ICStubCompiler {
-      protected:
-        ICStub* firstMonitorStub_;
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
-      public:
-        Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub)
-          : ICStubCompiler(cx, ICStub::GetProp_ArgumentsCallee, engine),
-            firstMonitorStub_(firstMonitorStub)
-        {}
-
-        ICStub* getStub(ICStubSpace* space) {
-            return newStub<ICGetProp_ArgumentsCallee>(space, getStubCode(), firstMonitorStub_);
-        }
-    };
-};
-
 // JSOP_NEWARRAY
 // JSOP_NEWINIT
 
 class ICNewArray_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     GCPtrObject templateObject_;
--- a/js/src/jit/SharedICList.h
+++ b/js/src/jit/SharedICList.h
@@ -31,18 +31,16 @@ namespace jit {
     _(Compare_String)                            \
     _(Compare_Boolean)                           \
     _(Compare_Object)                            \
     _(Compare_ObjectWithUndefined)               \
     _(Compare_Int32WithBoolean)                  \
                                                  \
     _(GetProp_Fallback)                          \
     _(GetProp_CallNativeGlobal)                  \
-    _(GetProp_ArgumentsLength)                   \
-    _(GetProp_ArgumentsCallee)                   \
     _(GetProp_Generic)                           \
                                                  \
     _(CacheIR_Monitored)                         \
                                                  \
 
 } // namespace jit
 } // namespace js