author | Leo Gaspard <leo@gaspard.io> |
Thu, 25 Aug 2016 16:28:31 -0700 | |
changeset 311966 | 26e6632de510d91ea6466008d2eda8f4cf25825f |
parent 311965 | 7a6d654175d2b2a0005d0cfcb48b20b1c18cd1b9 |
child 311967 | 77ed3ca61ef4fc2d32efc52b8dced0ada6c0bac0 |
push id | 30627 |
push user | ryanvm@gmail.com |
push date | Wed, 31 Aug 2016 13:15:23 +0000 |
treeherder | mozilla-central@3d9cabea1e56 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nbp |
bugs | 1283334 |
milestone | 51.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -85,16 +85,17 @@ GetObject(const MDefinition* ins) case MDefinition::Op_StoreElement: case MDefinition::Op_StoreUnboxedObjectOrNull: case MDefinition::Op_StoreUnboxedString: case MDefinition::Op_StoreUnboxedScalar: case MDefinition::Op_SetInitializedLength: 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: case MDefinition::Op_MaybeCopyElementsForWrite: case MDefinition::Op_MaybeToDoubleElement: case MDefinition::Op_UnboxedArrayLength: case MDefinition::Op_UnboxedArrayInitializedLength: case MDefinition::Op_IncrementUnboxedArrayInitializedLength:
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7970,17 +7970,18 @@ class OutOfLineStoreElementHole : public { LInstruction* ins_; Label rejoinStore_; public: 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) { codegen->visitOutOfLineStoreElementHole(this); } LInstruction* ins() const { return ins_; } @@ -8064,19 +8065,22 @@ CodeGenerator::visitStoreElementV(LStore masm.storeValue(value, dest); } else { BaseIndex dest(elements, ToRegister(lir->index()), TimesEight, lir->mir()->offsetAdjustment()); masm.storeValue(value, dest); } } -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()); Register obj = ToRegister(lir->object()); Register elements = ToRegister(lir->elements()); const LAllocation* index = lir->index(); RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index); @@ -8115,25 +8119,34 @@ CodeGenerator::visitStoreElementHoleT(LS masm.storeUnboxedProperty(address, unboxedType, v, nullptr); } } masm.bind(ool->rejoin()); } 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(); if (unboxedType == JSVAL_TYPE_MAGIC) { Address initLength(elements, ObjectElements::offsetOfInitializedLength()); masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry()); if (lir->mir()->needsBarrier()) @@ -8165,16 +8178,76 @@ CodeGenerator::visitStoreElementHoleV(LS masm.bind(ool->rejoinStore()); masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr); } } 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 = FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement, "SetDenseOrUnboxedArrayElement"); void CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool) @@ -8191,28 +8264,49 @@ CodeGenerator::visitOutOfLineStoreElemen LStoreElementHoleV* store = ins->toStoreElementHoleV(); object = ToRegister(store->object()); elements = ToRegister(store->elements()); index = store->index(); valueType = store->mir()->value()->type(); 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()); 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); + } 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); // If index == initializedLength, try to bump the initialized length inline. // If index > initializedLength, call a stub. Note that this relies on the // condition flags sticking from the incoming branch. Label callStub; @@ -8259,23 +8353,31 @@ CodeGenerator::visitOutOfLineStoreElemen // Update length if length < initializedLength. Address lengthAddr(object, UnboxedArrayObject::offsetOfLength()); Label dontUpdate; masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate); masm.add32(Imm32(1), lengthAddr); 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()); } masm.bind(&callStub); saveLive(ins);
--- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -293,18 +293,22 @@ class CodeGenerator final : public CodeG void visitLoadElementT(LLoadElementT* lir); void visitLoadElementV(LLoadElementV* load); void visitLoadElementHole(LLoadElementHole* lir); void visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir); void visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir); 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, Register elementsTemp, Register lengthTemp, TypedOrValueRegister out); void visitArrayPopShiftV(LArrayPopShiftV* lir); void visitArrayPopShiftT(LArrayPopShiftT* lir); void emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register obj, ConstantOrRegister value, Register elementsTemp, Register length);
--- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -3558,16 +3558,23 @@ jit::AddKeepAliveInstructions(MIRGraph& // StoreElementHole has an explicit object operand. If GVN // is disabled, we can get different unbox instructions with // the same object as input, so we check for that case. MOZ_ASSERT_IF(!use->toStoreElementHole()->object()->isUnbox() && !ownerObject->isUnbox(), use->toStoreElementHole()->object() == ownerObject); 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(), use->toInArray()->object() == ownerObject); continue; } if (!NeedsKeepAlive(ins, use))
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -10454,17 +10454,19 @@ IonBuilder::jsop_setelem_dense(Temporary { MIRType elementType = MIRType::None; if (unboxedType == JSVAL_TYPE_MAGIC) elementType = DenseNativeElementType(constraints(), obj); bool packed = ElementAccessIsPacked(constraints(), obj); // 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); current->add(idInt32); id = idInt32; if (NeedsPostBarrier(value)) current->add(MPostWriteElementBarrier::New(alloc(), obj, value, id)); @@ -10500,30 +10502,41 @@ IonBuilder::jsop_setelem_dense(Temporary default: MOZ_CRASH("Unknown double 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); } else { MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); store = ins; common = ins;
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3152,16 +3152,48 @@ LIRGenerator::visitStoreElementHole(MSto } } add(lir, 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) { MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment())); MOZ_ASSERT(ins->index()->type() == MIRType::Int32); MOZ_ASSERT(ins->value()->type() == MIRType::Object || ins->value()->type() == MIRType::Null || ins->value()->type() == MIRType::ObjectOrNull);
--- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -218,16 +218,17 @@ class LIRGenerator : public LIRGenerator void visitBoundsCheck(MBoundsCheck* ins); void visitBoundsCheckLower(MBoundsCheckLower* ins); void visitLoadElement(MLoadElement* ins); void visitLoadElementHole(MLoadElementHole* ins); void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins); 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); void visitEffectiveAddress(MEffectiveAddress* ins); void visitArrayPopShift(MArrayPopShift* ins); void visitArrayPush(MArrayPush* ins); void visitArraySlice(MArraySlice* ins); void visitArrayJoin(MArrayJoin* ins);
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2912,16 +2912,17 @@ NeedNegativeZeroCheck(MDefinition* def) MDefinition* rhs = use_def->toSub()->rhs(); if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) return true; MOZ_FALLTHROUGH; } case MDefinition::Op_StoreElement: case MDefinition::Op_StoreElementHole: + case MDefinition::Op_FallibleStoreElement: case MDefinition::Op_LoadElement: case MDefinition::Op_LoadElementHole: case MDefinition::Op_LoadUnboxedScalar: case MDefinition::Op_LoadTypedArrayElementHole: case MDefinition::Op_CharCodeAt: case MDefinition::Op_Mod: // Only allowed to remove check when definition is the second operand if (use_def->getOperand(0) == def) @@ -5705,16 +5706,23 @@ jit::ElementAccessIsPacked(CompilerConst bool jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj) { TemporaryTypeSet* types = obj->resultTypeSet(); 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) { TemporaryTypeSet* types = obj->resultTypeSet(); if (!types || types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_LENGTH_OVERFLOW)) return true; return TypeCanHaveExtraIndexedProperties(builder, types);
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9395,16 +9395,60 @@ class MStoreElementHole // or reallocate obj->elements. return AliasSet::Store(AliasSet::ObjectFields | AliasSet::BoxedOrUnboxedElements(unboxedType())); } 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>, public StoreUnboxedObjectOrNullPolicy::Data { int32_t offsetAdjustment_; bool preBarrier_; @@ -13885,16 +13929,17 @@ bool ElementAccessIsDenseNative(Compiler MDefinition* obj, MDefinition* id); JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id); bool ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, 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, CompilerConstraintList* constraints, TypeSet::ObjectKey* key, PropertyName* name, TemporaryTypeSet* observed, bool updateObserved); BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx, CompilerConstraintList* constraints,
--- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -207,16 +207,17 @@ namespace jit { _(InArray) \ _(LoadElement) \ _(LoadElementHole) \ _(LoadUnboxedScalar) \ _(LoadUnboxedObjectOrNull) \ _(LoadUnboxedString) \ _(StoreElement) \ _(StoreElementHole) \ + _(FallibleStoreElement) \ _(StoreUnboxedScalar) \ _(StoreUnboxedObjectOrNull) \ _(StoreUnboxedString) \ _(ConvertUnboxedObjectToNative) \ _(ArrayPopShift) \ _(ArrayPush) \ _(ArraySlice) \ _(ArrayJoin) \
--- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1294,16 +1294,25 @@ ThrowRuntimeLexicalError(JSContext* cx, { ScriptFrameIter iter(cx); RootedScript script(cx, iter.script()); ReportRuntimeLexicalError(cx, errorNumber, script, iter.pc()); 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) { ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr); return false; } bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
--- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -781,16 +781,18 @@ IonMarkFunction(MIRType type) } bool ObjectIsCallable(JSObject* obj); 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); MOZ_MUST_USE bool ThrowObjectCoercible(JSContext* cx, HandleValue v); MOZ_MUST_USE bool
--- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -5729,16 +5729,81 @@ class LStoreElementHoleT : public LInstr const LAllocation* index() { return getOperand(2); } const LAllocation* value() { return getOperand(3); } }; +// 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: LIR_HEADER(StoreUnboxedPointer) LStoreUnboxedPointer(LAllocation elements, LAllocation index, LAllocation value) { setOperand(0, elements); setOperand(1, index);
--- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -289,16 +289,18 @@ _(ArrayPopShiftV) \ _(ArrayPopShiftT) \ _(ArrayPushV) \ _(ArrayPushT) \ _(ArraySlice) \ _(ArrayJoin) \ _(StoreElementHoleV) \ _(StoreElementHoleT) \ + _(FallibleStoreElementV) \ + _(FallibleStoreElementT) \ _(LoadTypedArrayElementHole) \ _(LoadTypedArrayElementStatic) \ _(StoreTypedArrayElementHole) \ _(StoreTypedArrayElementStatic) \ _(AtomicIsLockFree) \ _(GuardSharedTypedArray) \ _(CompareExchangeTypedArrayElement) \ _(AtomicExchangeTypedArrayElement) \