Bug 1322091 part 3 - Port Baseline ArgumentsObject GETELEM stub to CacheIR. r=evilpie
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 09 Dec 2016 12:20:30 -1000
changeset 325614 ff00ebb732744d3196d30b8c1ce1c4feaf20db1a
parent 325613 b3249dd222cabf22cdf1f10a06d442ea5118db53
child 325615 70a0740cbd8129b84aabb426a50c3cf3240f8266
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersevilpie
bugs1322091
milestone53.0a1
Bug 1322091 part 3 - Port Baseline ArgumentsObject GETELEM stub to CacheIR. r=evilpie
js/src/jit/BaselineCacheIR.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineICList.h
js/src/jit/BaselineInspector.cpp
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
--- a/js/src/jit/BaselineCacheIR.cpp
+++ b/js/src/jit/BaselineCacheIR.cpp
@@ -1620,16 +1620,59 @@ BaselineCacheIRCompiler::emitLoadFrameAr
     masm.branch32(Assembler::AboveOrEqual, index, scratch, failure->label());
 
     // Load the argument.
     masm.loadValue(BaseValueIndex(BaselineFrameReg, index, BaselineFrame::offsetOfArg(0)), R0);
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitLoadArgumentsObjectArgResult()
+{
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    Register index = allocator.useRegister(masm, reader.int32OperandId());
+    AutoScratchRegister scratch(allocator, masm);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    // Get initial length value.
+    masm.unboxInt32(Address(obj, ArgumentsObject::getInitialLengthSlotOffset()), scratch);
+
+    // Ensure no overridden length/element.
+    masm.branchTest32(Assembler::NonZero,
+                      scratch,
+                      Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT |
+                            ArgumentsObject::ELEMENT_OVERRIDDEN_BIT),
+                      failure->label());
+
+    // Bounds check.
+    masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), scratch);
+    masm.branch32(Assembler::AboveOrEqual, index, scratch, failure->label());
+
+    // Load ArgumentsData.
+    masm.loadPrivate(Address(obj, ArgumentsObject::getDataSlotOffset()), scratch);
+
+    // Fail if we have a RareArgumentsData (elements were deleted).
+    masm.branchPtr(Assembler::NotEqual,
+                   Address(scratch, offsetof(ArgumentsData, rareData)),
+                   ImmWord(0),
+                   failure->label());
+
+    // Guard the argument is not a FORWARD_TO_CALL_SLOT MagicValue. Note that
+    // the order here matters: we should only clobber R0 after emitting the last
+    // guard.
+    BaseValueIndex argValue(scratch, index, ArgumentsData::offsetOfArgs());
+    masm.branchTestMagic(Assembler::Equal, argValue, failure->label());
+    masm.loadValue(argValue, R0);
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitTypeMonitorResult()
 {
     allocator.discardStack(masm);
     EmitEnterTypeMonitorIC(masm);
     return true;
 }
 
 bool
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -861,28 +861,16 @@ TypedArrayGetElemStubExists(ICGetElem_Fa
             continue;
         if (obj->maybeShape() == iter->toGetElem_TypedArray()->shape())
             return true;
     }
     return false;
 }
 
 static bool
-ArgumentsGetElemStubExists(ICGetElem_Fallback* stub, ICGetElem_Arguments::Which which)
-{
-    for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
-        if (!iter->isGetElem_Arguments())
-            continue;
-        if (iter->toGetElem_Arguments()->which() == which)
-            return true;
-    }
-    return false;
-}
-
-static bool
 IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId idp)
 {
     if (!key.isString())
         return false;
 
     // Convert to interned property name.
     if (!ValueToId<CanGC>(cx, key, idp))
         return false;
@@ -950,37 +938,16 @@ IsNativeOrUnboxedDenseElementAccess(Hand
 static bool
 TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_Fallback* stub,
                      HandleValue lhs, HandleValue rhs, HandleValue res, bool* attached)
 {
     if (!lhs.isObject())
         return true;
     RootedObject obj(cx, &lhs.toObject());
 
-    // Check for ArgumentsObj[int] accesses
-    if (obj->is<ArgumentsObject>() && rhs.isInt32() &&
-        !obj->as<ArgumentsObject>().hasOverriddenElement())
-    {
-        ICGetElem_Arguments::Which which = ICGetElem_Arguments::Mapped;
-        if (obj->is<UnmappedArgumentsObject>())
-            which = ICGetElem_Arguments::Unmapped;
-        if (!ArgumentsGetElemStubExists(stub, which)) {
-            JitSpew(JitSpew_BaselineIC, "  Generating GetElem(ArgsObj[Int32]) stub");
-            ICGetElem_Arguments::Compiler compiler(
-                cx, stub->fallbackMonitorStub()->firstMonitorStub(), which);
-            ICStub* argsStub = compiler.getStub(compiler.getStubSpace(script));
-            if (!argsStub)
-                return false;
-
-            stub->addNewStub(argsStub);
-            *attached = true;
-            return true;
-        }
-    }
-
     // Check for NativeObject[int] dense accesses.
     if (IsNativeDenseElementAccess(obj, rhs)) {
         JitSpew(JitSpew_BaselineIC, "  Generating GetElem(Native[Int32] dense) stub");
         ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                            obj->as<NativeObject>().lastProperty());
         ICStub* denseStub = compiler.getStub(compiler.getStubSpace(script));
         if (!denseStub)
             return false;
@@ -1335,103 +1302,16 @@ ICGetElem_TypedArray::Compiler::generate
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 //
-// GetElem_Arguments
-//
-bool
-ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    Label failure;
-    MOZ_ASSERT(which_ == ICGetElem_Arguments::Mapped ||
-               which_ == ICGetElem_Arguments::Unmapped);
-
-    const Class* clasp = (which_ == ICGetElem_Arguments::Mapped)
-                         ? &MappedArgumentsObject::class_
-                         : &UnmappedArgumentsObject::class_;
-
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
-    Register scratchReg = regs.takeAny();
-
-    // Guard on input being an arguments object.
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-    masm.branchTestObjClass(Assembler::NotEqual, objReg, scratchReg, clasp, &failure);
-
-    // Guard on index being int32
-    masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
-    Register idxReg = masm.extractInt32(R1, ExtractTemp1);
-
-    // Get initial ArgsObj length value.
-    masm.unboxInt32(Address(objReg, ArgumentsObject::getInitialLengthSlotOffset()), scratchReg);
-
-    // Test if length or any element have been overridden.
-    masm.branchTest32(Assembler::NonZero,
-                      scratchReg,
-                      Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT |
-                            ArgumentsObject::ELEMENT_OVERRIDDEN_BIT),
-                      &failure);
-
-    // Length has not been overridden, ensure that R1 is an integer and is <= length.
-    masm.rshiftPtr(Imm32(ArgumentsObject::PACKED_BITS_COUNT), scratchReg);
-    masm.branch32(Assembler::AboveOrEqual, idxReg, scratchReg, &failure);
-
-    // Length check succeeded, now check the correct bit.  We clobber potential type regs
-    // now.  Inputs will have to be reconstructed if we fail after this point, but that's
-    // unlikely.
-    Label failureReconstructInputs;
-    regs = availableGeneralRegs(0);
-    regs.takeUnchecked(objReg);
-    regs.takeUnchecked(idxReg);
-    regs.take(scratchReg);
-    Register argData = regs.takeAny();
-
-    // Load ArgumentsData
-    masm.loadPrivate(Address(objReg, ArgumentsObject::getDataSlotOffset()), argData);
-
-    // Fail if we have a RareArgumentsData (elements were deleted).
-    masm.branchPtr(Assembler::NotEqual,
-                   Address(argData, offsetof(ArgumentsData, rareData)),
-                   ImmWord(0),
-                   &failureReconstructInputs);
-
-    // Load the value. Use scratchReg to form a ValueOperand to load into.
-    masm.addPtr(Imm32(ArgumentsData::offsetOfArgs()), argData);
-    regs.add(scratchReg);
-    ValueOperand tempVal = regs.takeAnyValue();
-    masm.loadValue(BaseValueIndex(argData, idxReg), tempVal);
-
-    // Makesure that this is not a FORWARD_TO_CALL_SLOT magic value.
-    masm.branchTestMagic(Assembler::Equal, tempVal, &failureReconstructInputs);
-
-    // Copy value from temp to R0.
-    masm.moveValue(tempVal, R0);
-
-    // Type-check result
-    EmitEnterTypeMonitorIC(masm);
-
-    // Failed, but inputs are deconstructed into object and int, and need to be
-    // reconstructed into values.
-    masm.bind(&failureReconstructInputs);
-    masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
-    masm.tagValue(JSVAL_TYPE_INT32, idxReg, R1);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-//
 // SetElem_Fallback
 //
 
 static bool
 SetElemAddHasSameShapes(ICSetElem_DenseOrUnboxedArrayAdd* stub, JSObject* obj)
 {
     static const size_t MAX_DEPTH = ICSetElem_DenseOrUnboxedArrayAdd::MAX_PROTO_CHAIN_DEPTH;
     ICSetElem_DenseOrUnboxedArrayAddImpl<MAX_DEPTH>* nstub = stub->toImplUnchecked<MAX_DEPTH>();
@@ -7294,23 +7174,16 @@ ICGetElem_UnboxedArray::Clone(JSContext*
 ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type)
   : ICStub(GetElem_TypedArray, stubCode),
     shape_(shape)
 {
     extra_ = uint16_t(type);
     MOZ_ASSERT(extra_ == type);
 }
 
-/* static */ ICGetElem_Arguments*
-ICGetElem_Arguments::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                           ICGetElem_Arguments& other)
-{
-    return New<ICGetElem_Arguments>(cx, space, other.jitCode(), firstMonitorStub, other.which());
-}
-
 ICSetElem_DenseOrUnboxedArray::ICSetElem_DenseOrUnboxedArray(JitCode* stubCode, Shape* shape, ObjectGroup* group)
   : ICUpdatedStub(SetElem_DenseOrUnboxedArray, stubCode),
     shape_(shape),
     group_(group)
 { }
 
 ICSetElem_DenseOrUnboxedArrayAdd::ICSetElem_DenseOrUnboxedArrayAdd(JitCode* stubCode, ObjectGroup* group,
                                                                    size_t protoChainDepth)
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -555,63 +555,16 @@ class ICGetElem_TypedArray : public ICSt
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICGetElem_TypedArray>(space, getStubCode(), shape_, type_);
         }
     };
 };
 
-class ICGetElem_Arguments : public ICMonitoredStub
-{
-    friend class ICStubSpace;
-  public:
-    enum Which { Mapped, Unmapped };
-
-  private:
-    ICGetElem_Arguments(JitCode* stubCode, ICStub* firstMonitorStub, Which which)
-      : ICMonitoredStub(ICStub::GetElem_Arguments, stubCode, firstMonitorStub)
-    {
-        extra_ = static_cast<uint16_t>(which);
-    }
-
-  public:
-    static ICGetElem_Arguments* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                      ICGetElem_Arguments& other);
-
-    Which which() const {
-        return static_cast<Which>(extra_);
-    }
-
-    class Compiler : public ICStubCompiler {
-      ICStub* firstMonitorStub_;
-      Which which_;
-
-      protected:
-        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, ICStub* firstMonitorStub, Which which)
-          : ICStubCompiler(cx, ICStub::GetElem_Arguments, Engine::Baseline),
-            firstMonitorStub_(firstMonitorStub),
-            which_(which)
-        {}
-
-        ICStub* getStub(ICStubSpace* space) {
-            return newStub<ICGetElem_Arguments>(space, getStubCode(), firstMonitorStub_, which_);
-        }
-    };
-};
-
 // SetElem
 //      JSOP_SETELEM
 //      JSOP_INITELEM
 
 class ICSetElem_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -47,17 +47,16 @@ namespace jit {
     _(Call_ScriptedFunCall)                      \
     _(Call_StringSplit)                          \
     _(Call_IsSuspendedStarGenerator)             \
                                                  \
     _(GetElem_Fallback)                          \
     _(GetElem_Dense)                             \
     _(GetElem_UnboxedArray)                      \
     _(GetElem_TypedArray)                        \
-    _(GetElem_Arguments)                         \
                                                  \
     _(SetElem_Fallback)                          \
     _(SetElem_DenseOrUnboxedArray)               \
     _(SetElem_DenseOrUnboxedArrayAdd)            \
     _(SetElem_TypedArray)                        \
                                                  \
     _(In_Fallback)                               \
     _(In_Native)                                 \
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1011,20 +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::GetElem_Arguments:
-            // Either an object or magic arguments.
-            return MIRType::Value;
-
           case ICStub::GetElem_Dense:
           case ICStub::GetElem_TypedArray:
           case ICStub::GetElem_UnboxedArray:
             stubType = MIRType::Object;
             break;
 
           case ICStub::CacheIR_Monitored:
             stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored());
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -80,16 +80,23 @@ GetPropIRGenerator::tryAttachStub()
             if (tryAttachTypedObject(obj, objId, id))
                 return true;
             if (tryAttachModuleNamespace(obj, objId, id))
                 return true;
             if (tryAttachWindowProxy(obj, objId, id))
                 return true;
             if (tryAttachProxy(obj, objId, id))
                 return true;
+            return false;
+        }
+        if (idVal_.isInt32()) {
+            ValOperandId indexId = getElemKeyValueId();
+            if (tryAttachArgumentsObjectArg(obj, objId, indexId))
+                return true;
+            return false;
         }
         return false;
     }
 
     if (nameOrSymbol) {
         if (tryAttachPrimitive(valId, id))
             return true;
         if (tryAttachStringLength(valId, id))
@@ -845,16 +852,38 @@ GetPropIRGenerator::tryAttachMagicArgume
     writer.guardFrameHasNoArgumentsObject();
 
     Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
     writer.loadFrameArgumentResult(int32IndexId);
     writer.typeMonitorResult();
     return true;
 }
 
+bool
+GetPropIRGenerator::tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId,
+                                                ValOperandId indexId)
+{
+    MOZ_ASSERT(idVal_.isInt32());
+
+    if (!obj->is<ArgumentsObject>() || obj->as<ArgumentsObject>().hasOverriddenElement())
+        return false;
+
+    if (obj->is<MappedArgumentsObject>()) {
+        writer.guardClass(objId, GuardClassKind::MappedArguments);
+    } else {
+        MOZ_ASSERT(obj->is<UnmappedArgumentsObject>());
+        writer.guardClass(objId, GuardClassKind::UnmappedArguments);
+    }
+
+    Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
+    writer.loadArgumentsObjectArgResult(objId, int32IndexId);
+    writer.typeMonitorResult();
+    return true;
+}
+
 void
 GetPropIRGenerator::maybeEmitIdGuard(jsid id)
 {
     if (cacheKind_ == CacheKind::GetProp) {
         // Constant PropertyName, no guards necessary.
         MOZ_ASSERT(&idVal_.toString()->asAtom() == JSID_TO_ATOM(id));
         return;
     }
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -156,16 +156,17 @@ enum class CacheKind : uint8_t
                                           \
     /* The *Result ops load a value into the cache's result register. */ \
     _(LoadFixedSlotResult)                \
     _(LoadDynamicSlotResult)              \
     _(LoadUnboxedPropertyResult)          \
     _(LoadTypedObjectResult)              \
     _(LoadInt32ArrayLengthResult)         \
     _(LoadUnboxedArrayLengthResult)       \
+    _(LoadArgumentsObjectArgResult)       \
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadStringCharResult)               \
     _(LoadStringLengthResult)             \
     _(LoadFrameCalleeResult)              \
     _(LoadFrameNumActualArgsResult)       \
     _(LoadFrameArgumentResult)            \
     _(CallScriptedGetterResult)           \
     _(CallNativeGetterResult)             \
@@ -516,16 +517,20 @@ class MOZ_RAII CacheIRWriter : public JS
         addStubField(offset, StubField::Type::RawWord);
     }
     void loadInt32ArrayLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj);
     }
     void loadUnboxedArrayLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj);
     }
+    void loadArgumentsObjectArgResult(ObjOperandId obj, Int32OperandId index) {
+        writeOpWithOperandId(CacheOp::LoadArgumentsObjectArgResult, obj);
+        writeOperandId(index);
+    }
     void loadArgumentsObjectLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
     }
     void loadStringLengthResult(StringOperandId str) {
         writeOpWithOperandId(CacheOp::LoadStringLengthResult, str);
     }
     void loadStringCharResult(StringOperandId str, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::LoadStringCharResult, str);
@@ -646,17 +651,19 @@ class MOZ_RAII GetPropIRGenerator
     bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id);
 
     bool tryAttachPrimitive(ValOperandId valId, HandleId id);
     bool tryAttachStringChar(ValOperandId valId, ValOperandId indexId);
     bool tryAttachStringLength(ValOperandId valId, HandleId id);
     bool tryAttachMagicArgumentsName(ValOperandId valId, HandleId id);
+
     bool tryAttachMagicArgument(ValOperandId valId, ValOperandId indexId);
+    bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId, ValOperandId indexId);
 
     ValOperandId getElemKeyValueId() const {
         MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
         return ValOperandId(1);
     }
 
     // If this is a GetElem cache, emit instructions to guard the incoming Value
     // matches |id|.