зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1322091 part 3 - Port Baseline ArgumentsObject GETELEM stub to CacheIR. r=evilpie
--HG-- extra : rebase_source : b113f160c23ed4743b592b1d5d007a46b62393fb
This commit is contained in:
Родитель
bde1c4947f
Коммит
dc38fe3f57
|
@ -1624,6 +1624,49 @@ BaselineCacheIRCompiler::emitLoadFrameArgumentResult()
|
|||
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()
|
||||
{
|
||||
|
|
|
@ -865,18 +865,6 @@ TypedArrayGetElemStubExists(ICGetElem_Fallback* stub, HandleObject obj)
|
|||
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)
|
||||
{
|
||||
|
@ -955,27 +943,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
|
|||
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");
|
||||
|
@ -1339,93 +1306,6 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& 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
|
||||
//
|
||||
|
@ -7299,13 +7179,6 @@ ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scal
|
|||
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),
|
||||
|
|
|
@ -560,53 +560,6 @@ class ICGetElem_TypedArray : public ICStub
|
|||
};
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -52,7 +52,6 @@ namespace jit {
|
|||
_(GetElem_Dense) \
|
||||
_(GetElem_UnboxedArray) \
|
||||
_(GetElem_TypedArray) \
|
||||
_(GetElem_Arguments) \
|
||||
\
|
||||
_(SetElem_Fallback) \
|
||||
_(SetElem_DenseOrUnboxedArray) \
|
||||
|
|
|
@ -1016,10 +1016,6 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
|
|||
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:
|
||||
|
|
|
@ -85,6 +85,13 @@ GetPropIRGenerator::tryAttachStub()
|
|||
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;
|
||||
}
|
||||
|
@ -850,6 +857,28 @@ GetPropIRGenerator::tryAttachMagicArgument(ValOperandId valId, ValOperandId inde
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -161,6 +161,7 @@ enum class CacheKind : uint8_t
|
|||
_(LoadTypedObjectResult) \
|
||||
_(LoadInt32ArrayLengthResult) \
|
||||
_(LoadUnboxedArrayLengthResult) \
|
||||
_(LoadArgumentsObjectArgResult) \
|
||||
_(LoadArgumentsObjectLengthResult) \
|
||||
_(LoadStringCharResult) \
|
||||
_(LoadStringLengthResult) \
|
||||
|
@ -521,6 +522,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
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);
|
||||
}
|
||||
|
@ -651,7 +656,9 @@ class MOZ_RAII GetPropIRGenerator
|
|||
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче