--- 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|.