mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1283334 - Part 3: Do not sparsify dense arrays when freezing - Ion. r=nbp
--HG-- extra : rebase_source : 338ff0f30ed6c80da1b93c2fd1a847b5e57c2b7f extra : histedit_source : 3d60a20c97952902cdf07419887e39eb3316d8b5
This commit is contained in:
parent
07fa31ec7c
commit
cac188d1af
@ -90,6 +90,7 @@ GetObject(const MDefinition* ins)
|
||||
case MDefinition::Op_ArrayLength:
|
||||
case MDefinition::Op_SetArrayLength:
|
||||
case MDefinition::Op_StoreElementHole:
|
||||
case MDefinition::Op_FallibleStoreElement:
|
||||
case MDefinition::Op_TypedObjectDescr:
|
||||
case MDefinition::Op_Slots:
|
||||
case MDefinition::Op_Elements:
|
||||
|
@ -7975,7 +7975,8 @@ class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
|
||||
explicit OutOfLineStoreElementHole(LInstruction* ins)
|
||||
: ins_(ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->isStoreElementHoleV() || ins->isStoreElementHoleT());
|
||||
MOZ_ASSERT(ins->isStoreElementHoleV() || ins->isStoreElementHoleT() ||
|
||||
ins->isFallibleStoreElementV() || ins->isFallibleStoreElementT());
|
||||
}
|
||||
|
||||
void accept(CodeGenerator* codegen) {
|
||||
@ -8069,9 +8070,12 @@ CodeGenerator::visitStoreElementV(LStoreElementV* lir)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
|
||||
template <typename T> void
|
||||
CodeGenerator::emitStoreElementHoleT(T* lir)
|
||||
{
|
||||
static_assert(std::is_same<T, LStoreElementHoleT>::value || std::is_same<T, LFallibleStoreElementT>::value,
|
||||
"emitStoreElementHoleT called with unexpected argument type");
|
||||
|
||||
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
@ -8120,15 +8124,24 @@ CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
|
||||
CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
|
||||
{
|
||||
emitStoreElementHoleT(lir);
|
||||
}
|
||||
|
||||
template <typename T> void
|
||||
CodeGenerator::emitStoreElementHoleV(T* lir)
|
||||
{
|
||||
static_assert(std::is_same<T, LStoreElementHoleV>::value || std::is_same<T, LFallibleStoreElementV>::value,
|
||||
"emitStoreElementHoleV called with unexpected parameter type");
|
||||
|
||||
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register elements = ToRegister(lir->elements());
|
||||
const LAllocation* index = lir->index();
|
||||
const ValueOperand value = ToValue(lir, LStoreElementHoleV::Value);
|
||||
const ValueOperand value = ToValue(lir, T::Value);
|
||||
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
|
||||
|
||||
JSValueType unboxedType = lir->mir()->unboxedType();
|
||||
@ -8170,6 +8183,66 @@ CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
|
||||
{
|
||||
emitStoreElementHoleV(lir);
|
||||
}
|
||||
|
||||
typedef bool (*ThrowReadOnlyFn)(JSContext*, HandleObject);
|
||||
static const VMFunction ThrowReadOnlyInfo =
|
||||
FunctionInfo<ThrowReadOnlyFn>(ThrowReadOnlyError, "ThrowReadOnlyError");
|
||||
|
||||
void
|
||||
CodeGenerator::visitFallibleStoreElementT(LFallibleStoreElementT* lir)
|
||||
{
|
||||
Register elements = ToRegister(lir->elements());
|
||||
|
||||
// Handle frozen objects
|
||||
Label isFrozen;
|
||||
Address flags(elements, ObjectElements::offsetOfFlags());
|
||||
if (!lir->mir()->strict()) {
|
||||
masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
|
||||
} else {
|
||||
Register object = ToRegister(lir->object());
|
||||
OutOfLineCode* ool = oolCallVM(ThrowReadOnlyInfo, lir,
|
||||
ArgList(object), StoreNothing());
|
||||
masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
|
||||
// This OOL code should have thrown an exception, so will never return.
|
||||
// So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
|
||||
// of a jump) does a masm.assumeUnreachable().
|
||||
}
|
||||
|
||||
emitStoreElementHoleT(lir);
|
||||
|
||||
masm.bind(&isFrozen);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir)
|
||||
{
|
||||
Register elements = ToRegister(lir->elements());
|
||||
|
||||
// Handle frozen objects
|
||||
Label isFrozen;
|
||||
Address flags(elements, ObjectElements::offsetOfFlags());
|
||||
if (!lir->mir()->strict()) {
|
||||
masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
|
||||
} else {
|
||||
Register object = ToRegister(lir->object());
|
||||
OutOfLineCode* ool = oolCallVM(ThrowReadOnlyInfo, lir,
|
||||
ArgList(object), StoreNothing());
|
||||
masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
|
||||
// This OOL code should have thrown an exception, so will never return.
|
||||
// So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
|
||||
// of a jump) does a masm.assumeUnreachable().
|
||||
}
|
||||
|
||||
emitStoreElementHoleV(lir);
|
||||
|
||||
masm.bind(&isFrozen);
|
||||
}
|
||||
|
||||
typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
|
||||
HandleValue, bool strict);
|
||||
static const VMFunction SetDenseOrUnboxedArrayElementInfo =
|
||||
@ -8196,7 +8269,16 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
|
||||
unboxedType = store->mir()->unboxedType();
|
||||
temp = store->getTemp(0);
|
||||
} else {
|
||||
} else if (ins->isFallibleStoreElementV()) {
|
||||
LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
|
||||
object = ToRegister(store->object());
|
||||
elements = ToRegister(store->elements());
|
||||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
|
||||
unboxedType = store->mir()->unboxedType();
|
||||
temp = store->getTemp(0);
|
||||
} else if (ins->isStoreElementHoleT()) {
|
||||
LStoreElementHoleT* store = ins->toStoreElementHoleT();
|
||||
object = ToRegister(store->object());
|
||||
elements = ToRegister(store->elements());
|
||||
@ -8208,6 +8290,18 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
unboxedType = store->mir()->unboxedType();
|
||||
temp = store->getTemp(0);
|
||||
} else { // ins->isFallibleStoreElementT()
|
||||
LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
|
||||
object = ToRegister(store->object());
|
||||
elements = ToRegister(store->elements());
|
||||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
if (store->value()->isConstant())
|
||||
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
unboxedType = store->mir()->unboxedType();
|
||||
temp = store->getTemp(0);
|
||||
}
|
||||
|
||||
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
|
||||
@ -8264,13 +8358,21 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||
masm.bind(&dontUpdate);
|
||||
}
|
||||
|
||||
if (ins->isStoreElementHoleT() && unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double) {
|
||||
// The inline path for StoreElementHoleT does not always store the type tag,
|
||||
// so we do the store on the OOL path. We use MIRType::None for the element type
|
||||
// so that storeElementTyped will always store the type tag.
|
||||
emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType::None,
|
||||
elements, index, 0);
|
||||
masm.jump(ool->rejoin());
|
||||
if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
|
||||
unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double)
|
||||
{
|
||||
// The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
|
||||
// the type tag, so we do the store on the OOL path. We use MIRType::None for the element
|
||||
// type so that storeElementTyped will always store the type tag.
|
||||
if (ins->isStoreElementHoleT()) {
|
||||
emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType::None,
|
||||
elements, index, 0);
|
||||
masm.jump(ool->rejoin());
|
||||
} else if (ins->isFallibleStoreElementT()) {
|
||||
emitStoreElementTyped(ins->toFallibleStoreElementT()->value(), valueType,
|
||||
MIRType::None, elements, index, 0);
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
} else {
|
||||
// Jump to the inline path where we will store the value.
|
||||
masm.jump(ool->rejoinStore());
|
||||
|
@ -298,8 +298,12 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||
void visitUnboxObjectOrNull(LUnboxObjectOrNull* lir);
|
||||
void visitStoreElementT(LStoreElementT* lir);
|
||||
void visitStoreElementV(LStoreElementV* lir);
|
||||
template <typename T> void emitStoreElementHoleT(T* lir);
|
||||
template <typename T> void emitStoreElementHoleV(T* lir);
|
||||
void visitStoreElementHoleT(LStoreElementHoleT* lir);
|
||||
void visitStoreElementHoleV(LStoreElementHoleV* lir);
|
||||
void visitFallibleStoreElementV(LFallibleStoreElementV* lir);
|
||||
void visitFallibleStoreElementT(LFallibleStoreElementT* lir);
|
||||
void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir);
|
||||
void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir);
|
||||
void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
|
||||
|
@ -3563,6 +3563,13 @@ jit::AddKeepAliveInstructions(MIRGraph& graph)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use->isFallibleStoreElement()) {
|
||||
// See StoreElementHole case above.
|
||||
MOZ_ASSERT_IF(!use->toFallibleStoreElement()->object()->isUnbox() && !ownerObject->isUnbox(),
|
||||
use->toFallibleStoreElement()->object() == ownerObject);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use->isInArray()) {
|
||||
// See StoreElementHole case above.
|
||||
MOZ_ASSERT_IF(!use->toInArray()->object()->isUnbox() && !ownerObject->isUnbox(),
|
||||
|
@ -10459,7 +10459,9 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||
|
||||
// Writes which are on holes in the object do not have to bail out if they
|
||||
// cannot hit another indexed property on the object or its prototypes.
|
||||
bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(this, obj);
|
||||
bool hasNoExtraIndexedProperty = !ElementAccessHasExtraIndexedProperty(this, obj);
|
||||
|
||||
bool mayBeFrozen = ElementAccessMightBeFrozen(constraints(), obj);
|
||||
|
||||
// Ensure id is an integer.
|
||||
MInstruction* idInt32 = MToInt32::New(alloc(), id);
|
||||
@ -10505,20 +10507,31 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
|
||||
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
|
||||
// the initialized length and bounds check.
|
||||
// If an object may have been frozen, no previous expectation hold and we
|
||||
// fallback to MFallibleStoreElement.
|
||||
MInstruction* store;
|
||||
MStoreElementCommon *common = nullptr;
|
||||
if (writeHole && writeOutOfBounds) {
|
||||
if (writeHole && hasNoExtraIndexedProperty && !mayBeFrozen) {
|
||||
MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue, unboxedType);
|
||||
store = ins;
|
||||
common = ins;
|
||||
|
||||
current->add(ins);
|
||||
current->push(value);
|
||||
} else if (hasNoExtraIndexedProperty && mayBeFrozen) {
|
||||
bool strict = IsStrictSetPC(pc);
|
||||
MFallibleStoreElement* ins = MFallibleStoreElement::New(alloc(), obj, elements, id,
|
||||
newValue, unboxedType, strict);
|
||||
store = ins;
|
||||
common = ins;
|
||||
|
||||
current->add(ins);
|
||||
current->push(value);
|
||||
} else {
|
||||
MInstruction* initLength = initializedLength(obj, elements, unboxedType);
|
||||
|
||||
id = addBoundsCheck(id, initLength);
|
||||
bool needsHoleCheck = !packed && !writeOutOfBounds;
|
||||
bool needsHoleCheck = !packed && !hasNoExtraIndexedProperty;
|
||||
|
||||
if (unboxedType != JSVAL_TYPE_MAGIC) {
|
||||
store = storeUnboxedValue(obj, elements, 0, id, unboxedType, newValue);
|
||||
|
@ -3156,6 +3156,38 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
|
||||
MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
|
||||
|
||||
const LUse object = useRegister(ins->object());
|
||||
const LUse elements = useRegister(ins->elements());
|
||||
const LAllocation index = useRegisterOrConstant(ins->index());
|
||||
|
||||
// Use a temp register when adding new elements to unboxed arrays.
|
||||
LDefinition tempDef = LDefinition::BogusTemp();
|
||||
if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
|
||||
tempDef = temp();
|
||||
|
||||
LInstruction* lir;
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
|
||||
tempDef);
|
||||
break;
|
||||
default:
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value, tempDef);
|
||||
break;
|
||||
}
|
||||
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins)
|
||||
{
|
||||
|
@ -223,6 +223,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitLoadUnboxedString(MLoadUnboxedString* ins);
|
||||
void visitStoreElement(MStoreElement* ins);
|
||||
void visitStoreElementHole(MStoreElementHole* ins);
|
||||
void visitFallibleStoreElement(MFallibleStoreElement* ins);
|
||||
void visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins);
|
||||
void visitStoreUnboxedString(MStoreUnboxedString* ins);
|
||||
void visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins);
|
||||
|
@ -2917,6 +2917,7 @@ NeedNegativeZeroCheck(MDefinition* def)
|
||||
}
|
||||
case MDefinition::Op_StoreElement:
|
||||
case MDefinition::Op_StoreElementHole:
|
||||
case MDefinition::Op_FallibleStoreElement:
|
||||
case MDefinition::Op_LoadElement:
|
||||
case MDefinition::Op_LoadElementHole:
|
||||
case MDefinition::Op_LoadUnboxedScalar:
|
||||
@ -5691,6 +5692,13 @@ jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefin
|
||||
return !types || types->hasObjectFlags(constraints, OBJECT_FLAG_COPY_ON_WRITE);
|
||||
}
|
||||
|
||||
bool
|
||||
jit::ElementAccessMightBeFrozen(CompilerConstraintList* constraints, MDefinition* obj)
|
||||
{
|
||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
||||
return !types || types->hasObjectFlags(constraints, OBJECT_FLAG_FROZEN);
|
||||
}
|
||||
|
||||
bool
|
||||
jit::ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj)
|
||||
{
|
||||
|
@ -9400,6 +9400,50 @@ class MStoreElementHole
|
||||
ALLOW_CLONE(MStoreElementHole)
|
||||
};
|
||||
|
||||
// Try to store a value to a dense array slots vector. May fail due to the object being frozen.
|
||||
// Cannot be used on an object that has extra indexed properties.
|
||||
class MFallibleStoreElement
|
||||
: public MAryInstruction<4>,
|
||||
public MStoreElementCommon,
|
||||
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
|
||||
{
|
||||
JSValueType unboxedType_;
|
||||
bool strict_;
|
||||
|
||||
MFallibleStoreElement(MDefinition* object, MDefinition* elements,
|
||||
MDefinition* index, MDefinition* value,
|
||||
JSValueType unboxedType, bool strict)
|
||||
: unboxedType_(unboxedType)
|
||||
{
|
||||
initOperand(0, object);
|
||||
initOperand(1, elements);
|
||||
initOperand(2, index);
|
||||
initOperand(3, value);
|
||||
strict_ = strict;
|
||||
MOZ_ASSERT(elements->type() == MIRType::Elements);
|
||||
MOZ_ASSERT(index->type() == MIRType::Int32);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(FallibleStoreElement)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
|
||||
|
||||
JSValueType unboxedType() const {
|
||||
return unboxedType_;
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::Store(AliasSet::ObjectFields |
|
||||
AliasSet::BoxedOrUnboxedElements(unboxedType()));
|
||||
}
|
||||
bool strict() const {
|
||||
return strict_;
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MFallibleStoreElement)
|
||||
};
|
||||
|
||||
|
||||
// Store an unboxed object or null pointer to a v\ector.
|
||||
class MStoreUnboxedObjectOrNull
|
||||
: public MAryInstruction<4>,
|
||||
@ -13877,6 +13921,7 @@ bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
|
||||
Scalar::Type* arrayType);
|
||||
bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
|
||||
bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
|
||||
bool ElementAccessMightBeFrozen(CompilerConstraintList* constraints, MDefinition* obj);
|
||||
bool ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
|
||||
MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
|
||||
BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
|
||||
|
@ -212,6 +212,7 @@ namespace jit {
|
||||
_(LoadUnboxedString) \
|
||||
_(StoreElement) \
|
||||
_(StoreElementHole) \
|
||||
_(FallibleStoreElement) \
|
||||
_(StoreUnboxedScalar) \
|
||||
_(StoreUnboxedObjectOrNull) \
|
||||
_(StoreUnboxedString) \
|
||||
|
@ -1298,6 +1298,15 @@ ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowReadOnlyError(JSContext* cx, HandleObject handle)
|
||||
{
|
||||
HandleNativeObject obj = handle.as<NativeObject>();
|
||||
RootedValue val(cx, ObjectValue(*obj));
|
||||
ReportValueError(cx, JSMSG_READ_ONLY, JSDVG_IGNORE_STACK, val, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
|
||||
{
|
||||
|
@ -786,6 +786,8 @@ bool ObjectIsConstructor(JSObject* obj);
|
||||
MOZ_MUST_USE bool
|
||||
ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber);
|
||||
MOZ_MUST_USE bool
|
||||
ThrowReadOnlyError(JSContext* cx, HandleObject obj);
|
||||
MOZ_MUST_USE bool
|
||||
BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
|
||||
MOZ_MUST_USE bool
|
||||
ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
|
||||
|
@ -5734,6 +5734,71 @@ class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(FallibleStoreElementV)
|
||||
|
||||
LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LBoxAllocation& value,
|
||||
const LDefinition& temp) {
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
static const size_t Value = 3;
|
||||
|
||||
const MFallibleStoreElement* mir() const {
|
||||
return mir_->toFallibleStoreElement();
|
||||
}
|
||||
const LAllocation* object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* elements() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(FallibleStoreElementT)
|
||||
|
||||
LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& temp) {
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const MFallibleStoreElement* mir() const {
|
||||
return mir_->toFallibleStoreElement();
|
||||
}
|
||||
const LAllocation* object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* elements() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
};
|
||||
|
||||
class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -294,6 +294,8 @@
|
||||
_(ArrayJoin) \
|
||||
_(StoreElementHoleV) \
|
||||
_(StoreElementHoleT) \
|
||||
_(FallibleStoreElementV) \
|
||||
_(FallibleStoreElementT) \
|
||||
_(LoadTypedArrayElementHole) \
|
||||
_(LoadTypedArrayElementStatic) \
|
||||
_(StoreTypedArrayElementHole) \
|
||||
|
Loading…
Reference in New Issue
Block a user