зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1445235 part 6 - Use spectreBoundsCheck32 for more stores in JIT code. r=nbp
This commit is contained in:
Родитель
f9a2b1497d
Коммит
b82103f0d5
|
@ -1380,9 +1380,11 @@ BaselineCacheIRCompiler::emitStoreDenseElement()
|
|||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
|
||||
// Bounds check.
|
||||
// Bounds check. Unfortunately we don't have more registers available on
|
||||
// x86, so use InvalidReg and emit slightly slower code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
|
||||
|
||||
// Hole check.
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
|
@ -1471,18 +1473,30 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
ObjectElements::FROZEN),
|
||||
failure->label());
|
||||
|
||||
// We don't have enough registers on x86 so use InvalidReg. This will emit
|
||||
// slightly less efficient code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
|
||||
if (handleAdd) {
|
||||
// Fail if index > initLength.
|
||||
masm.branch32(Assembler::Below, initLength, index, failure->label());
|
||||
// Bounds check.
|
||||
Label capacityOk, outOfBounds;
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// If we're out-of-bounds, only handle the index == initLength case.
|
||||
masm.bind(&outOfBounds);
|
||||
masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
|
||||
|
||||
// If index < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Label allocElement;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, index, &capacityOk);
|
||||
masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
masm.bind(&allocElement);
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
@ -1510,7 +1524,7 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
// the type update code doesn't read uninitialized memory.
|
||||
} else {
|
||||
// Fail if index >= initLength.
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, failure->label());
|
||||
}
|
||||
|
||||
// Check if we have to convert a double element.
|
||||
|
@ -1595,10 +1609,9 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.load32(Address(scratch, ObjectElements::offsetOfLength()), scratchLength);
|
||||
|
||||
BaseObjectElementIndex element(scratch, scratchLength);
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
Address elementsInitLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
Address elementsLength(scratch, ObjectElements::offsetOfLength());
|
||||
Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
|
||||
|
||||
// Check for copy-on-write or frozen elements.
|
||||
|
@ -1608,16 +1621,19 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
failure->label());
|
||||
|
||||
// Fail if length != initLength.
|
||||
masm.branch32(Assembler::NotEqual, initLength, scratchLength, failure->label());
|
||||
masm.load32(elementsInitLength, scratchLength);
|
||||
masm.branch32(Assembler::NotEqual, elementsLength, scratchLength, failure->label());
|
||||
|
||||
// If scratchLength < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Label capacityOk, allocElement;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, scratchLength, &capacityOk);
|
||||
masm.spectreBoundsCheck32(scratchLength, capacity, InvalidReg, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
masm.bind(&allocElement);
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
@ -1672,12 +1688,12 @@ BaselineCacheIRCompiler::emitArrayPush()
|
|||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
|
||||
// Increment initLength and length.
|
||||
Address length(scratch, ObjectElements::offsetOfLength());
|
||||
masm.add32(Imm32(1), initLength);
|
||||
masm.load32(length, scratchLength);
|
||||
masm.add32(Imm32(1), length);
|
||||
masm.add32(Imm32(1), elementsInitLength);
|
||||
masm.load32(elementsLength, scratchLength);
|
||||
masm.add32(Imm32(1), elementsLength);
|
||||
|
||||
// Store the value.
|
||||
BaseObjectElementIndex element(scratch, scratchLength);
|
||||
masm.storeValue(val, element);
|
||||
emitPostBarrierElement(obj, val, scratch, scratchLength);
|
||||
|
||||
|
@ -1708,7 +1724,11 @@ BaselineCacheIRCompiler::emitStoreTypedElement()
|
|||
// Bounds check.
|
||||
Label done;
|
||||
LoadTypedThingLength(masm, layout, obj, scratch1);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
|
||||
|
||||
// Unfortunately we don't have more registers available on x86, so use
|
||||
// InvalidReg and emit slightly slower code on x86.
|
||||
Register spectreTemp = InvalidReg;
|
||||
masm.spectreBoundsCheck32(index, scratch1, spectreTemp, handleOOB ? &done : failure->label());
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout, obj, scratch1);
|
||||
|
|
|
@ -9227,9 +9227,10 @@ CodeGenerator::emitStoreElementHoleT(T* lir)
|
|||
|
||||
Register elements = ToRegister(lir->elements());
|
||||
Register index = ToRegister(lir->index());
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
|
||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, ool->entry());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
|
||||
|
||||
if (lir->mir()->needsBarrier())
|
||||
emitPreBarrier(elements, lir->index(), 0);
|
||||
|
@ -9260,9 +9261,10 @@ CodeGenerator::emitStoreElementHoleV(T* lir)
|
|||
Register elements = ToRegister(lir->elements());
|
||||
Register index = ToRegister(lir->index());
|
||||
const ValueOperand value = ToValue(lir, T::Value);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
|
||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, ool->entry());
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, ool->entry());
|
||||
|
||||
if (lir->mir()->needsBarrier())
|
||||
emitPreBarrier(elements, lir->index(), 0);
|
||||
|
@ -9360,6 +9362,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
const LAllocation* index;
|
||||
MIRType valueType;
|
||||
ConstantOrRegister value;
|
||||
Register spectreTemp;
|
||||
|
||||
if (ins->isStoreElementHoleV()) {
|
||||
LStoreElementHoleV* store = ins->toStoreElementHoleV();
|
||||
|
@ -9368,6 +9371,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else if (ins->isFallibleStoreElementV()) {
|
||||
LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9375,6 +9379,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
index = store->index();
|
||||
valueType = store->mir()->value()->type();
|
||||
value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else if (ins->isStoreElementHoleT()) {
|
||||
LStoreElementHoleT* store = ins->toStoreElementHoleT();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9385,6 +9390,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
} else { // ins->isFallibleStoreElementT()
|
||||
LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
|
||||
object = ToRegister(store->object());
|
||||
|
@ -9395,6 +9401,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||
spectreTemp = ToTempRegisterOrInvalid(store->spectreTemp());
|
||||
}
|
||||
|
||||
Register indexReg = ToRegister(index);
|
||||
|
@ -9402,6 +9409,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
// 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.
|
||||
// Also note: this branch does not need Spectre mitigations, doing that for
|
||||
// the capacity check below is sufficient.
|
||||
Label callStub;
|
||||
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
// Had to reimplement for MIPS because there are no flags.
|
||||
|
@ -9412,8 +9421,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
|||
#endif
|
||||
|
||||
// Check array capacity.
|
||||
masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
|
||||
indexReg, &callStub);
|
||||
masm.spectreBoundsCheck32(indexReg, Address(elements, ObjectElements::offsetOfCapacity()),
|
||||
spectreTemp, &callStub);
|
||||
|
||||
// Update initialized length. The capacity guard above ensures this won't overflow,
|
||||
// due to MAX_DENSE_ELEMENTS_COUNT.
|
||||
|
@ -9558,12 +9567,13 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
|
|||
// VM call if a write barrier is necessary.
|
||||
masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
|
||||
|
||||
// Load elements and length, and VM call if length != initializedLength.
|
||||
// Load elements and initializedLength, and VM call if
|
||||
// length != initializedLength.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
|
||||
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
|
||||
masm.load32(Address(elementsTemp, ObjectElements::offsetOfInitializedLength()), lengthTemp);
|
||||
|
||||
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::NotEqual, initLength, lengthTemp, ool->entry());
|
||||
Address lengthAddr(elementsTemp, ObjectElements::offsetOfLength());
|
||||
masm.branch32(Assembler::NotEqual, lengthAddr, lengthTemp, ool->entry());
|
||||
|
||||
// Test for length != 0. On zero length either take a VM call or generate
|
||||
// an undefined value, depending on whether the call is known to produce
|
||||
|
@ -9655,7 +9665,8 @@ static const VMFunction ArrayPushDenseInfo =
|
|||
|
||||
void
|
||||
CodeGenerator::emitArrayPush(LInstruction* lir, Register obj,
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length)
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length,
|
||||
Register spectreTemp)
|
||||
{
|
||||
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
|
||||
|
||||
|
@ -9669,7 +9680,7 @@ CodeGenerator::emitArrayPush(LInstruction* lir, Register obj,
|
|||
|
||||
// Guard length < capacity.
|
||||
Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::BelowOrEqual, capacity, length, ool->entry());
|
||||
masm.spectreBoundsCheck32(length, capacity, spectreTemp, ool->entry());
|
||||
|
||||
// Do the store.
|
||||
masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
|
||||
|
@ -9690,7 +9701,8 @@ CodeGenerator::visitArrayPushV(LArrayPushV* lir)
|
|||
Register elementsTemp = ToRegister(lir->temp());
|
||||
Register length = ToRegister(lir->output());
|
||||
ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9704,7 +9716,8 @@ CodeGenerator::visitArrayPushT(LArrayPushT* lir)
|
|||
value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
|
||||
else
|
||||
value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length);
|
||||
Register spectreTemp = ToTempRegisterOrInvalid(lir->spectreTemp());
|
||||
emitArrayPush(lir, obj, value, elementsTemp, length, spectreTemp);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
|
||||
|
|
|
@ -163,7 +163,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
|
||||
Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
|
||||
void emitArrayPush(LInstruction* lir, Register obj,
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length);
|
||||
const ConstantOrRegister& value, Register elementsTemp, Register length,
|
||||
Register spectreTemp);
|
||||
|
||||
void emitRest(LInstruction* lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
|
|
|
@ -1901,7 +1901,8 @@ IonCacheIRCompiler::emitStoreDenseElement()
|
|||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1910,20 +1911,20 @@ IonCacheIRCompiler::emitStoreDenseElement()
|
|||
EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
|
||||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
// Bounds check.
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
masm.branch32(Assembler::BelowOrEqual, initLength, index, failure->label());
|
||||
Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
|
||||
masm.spectreBoundsCheck32(index, initLength, scratch2, failure->label());
|
||||
|
||||
// Hole check.
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
BaseObjectElementIndex element(scratch1, index);
|
||||
masm.branchTestMagic(Assembler::Equal, element, failure->label());
|
||||
|
||||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
EmitStoreDenseElement(masm, val, scratch, element);
|
||||
EmitStoreDenseElement(masm, val, scratch1, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
emitPostBarrierElement(obj, val, scratch1, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1939,7 +1940,8 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
// track this.
|
||||
reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -1947,45 +1949,51 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
|
||||
EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
|
||||
|
||||
// Load obj->elements in scratch.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
// Load obj->elements in scratch1.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
Address initLength(scratch, ObjectElements::offsetOfInitializedLength());
|
||||
BaseObjectElementIndex element(scratch, index);
|
||||
Address initLength(scratch1, ObjectElements::offsetOfInitializedLength());
|
||||
BaseObjectElementIndex element(scratch1, index);
|
||||
|
||||
Label inBounds, doStore;
|
||||
masm.branch32(Assembler::Above, initLength, index, &inBounds);
|
||||
Label inBounds, outOfBounds;
|
||||
Register spectreTemp = scratch2;
|
||||
masm.spectreBoundsCheck32(index, initLength, spectreTemp, &outOfBounds);
|
||||
masm.jump(&inBounds);
|
||||
|
||||
masm.bind(&outOfBounds);
|
||||
masm.branch32(Assembler::NotEqual, initLength, index, failure->label());
|
||||
|
||||
// If index < capacity, we can add a dense element inline. If not we
|
||||
// need to allocate more elements.
|
||||
Label capacityOk;
|
||||
Address capacity(scratch, ObjectElements::offsetOfCapacity());
|
||||
masm.branch32(Assembler::Above, capacity, index, &capacityOk);
|
||||
Label capacityOk, allocElement;
|
||||
Address capacity(scratch1, ObjectElements::offsetOfCapacity());
|
||||
masm.spectreBoundsCheck32(index, capacity, spectreTemp, &allocElement);
|
||||
masm.jump(&capacityOk);
|
||||
|
||||
// Check for non-writable array length. We only have to do this if
|
||||
// index >= capacity.
|
||||
Address elementsFlags(scratch, ObjectElements::offsetOfFlags());
|
||||
masm.bind(&allocElement);
|
||||
Address elementsFlags(scratch1, ObjectElements::offsetOfFlags());
|
||||
masm.branchTest32(Assembler::NonZero, elementsFlags,
|
||||
Imm32(ObjectElements::NONWRITABLE_ARRAY_LENGTH),
|
||||
failure->label());
|
||||
|
||||
LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
|
||||
save.takeUnchecked(scratch);
|
||||
save.takeUnchecked(scratch1);
|
||||
masm.PushRegsInMask(save);
|
||||
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.setupUnalignedABICall(scratch1);
|
||||
masm.loadJSContext(scratch1);
|
||||
masm.passABIArg(scratch1);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
|
||||
masm.mov(ReturnReg, scratch);
|
||||
masm.mov(ReturnReg, scratch1);
|
||||
|
||||
masm.PopRegsInMask(save);
|
||||
masm.branchIfFalseBool(scratch, failure->label());
|
||||
masm.branchIfFalseBool(scratch1, failure->label());
|
||||
|
||||
// Load the reallocated elements pointer.
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
|
||||
|
||||
masm.bind(&capacityOk);
|
||||
|
||||
|
@ -1994,12 +2002,13 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
|
||||
// If length is now <= index, increment length too.
|
||||
Label skipIncrementLength;
|
||||
Address length(scratch, ObjectElements::offsetOfLength());
|
||||
Address length(scratch1, ObjectElements::offsetOfLength());
|
||||
masm.branch32(Assembler::Above, length, index, &skipIncrementLength);
|
||||
masm.add32(Imm32(1), length);
|
||||
masm.bind(&skipIncrementLength);
|
||||
|
||||
// Skip EmitPreBarrier as the memory is uninitialized.
|
||||
Label doStore;
|
||||
masm.jump(&doStore);
|
||||
|
||||
masm.bind(&inBounds);
|
||||
|
@ -2007,9 +2016,9 @@ IonCacheIRCompiler::emitStoreDenseElementHole()
|
|||
EmitPreBarrier(masm, element, MIRType::Value);
|
||||
|
||||
masm.bind(&doStore);
|
||||
EmitStoreDenseElement(masm, val, scratch, element);
|
||||
EmitStoreDenseElement(masm, val, scratch1, element);
|
||||
if (needsPostBarrier())
|
||||
emitPostBarrierElement(obj, val, scratch, index);
|
||||
emitPostBarrierElement(obj, val, scratch1, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2032,10 +2041,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
bool handleOOB = reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
|
||||
Maybe<AutoScratchRegister> scratch2;
|
||||
if (arrayType != Scalar::Float32 && arrayType != Scalar::Float64)
|
||||
scratch2.emplace(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
|
@ -2044,7 +2050,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
// Bounds check.
|
||||
Label done;
|
||||
LoadTypedThingLength(masm, layout, obj, scratch1);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
|
||||
masm.spectreBoundsCheck32(index, scratch1, scratch2, handleOOB ? &done : failure->label());
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout, obj, scratch1);
|
||||
|
@ -2066,7 +2072,7 @@ IonCacheIRCompiler::emitStoreTypedElement()
|
|||
return false;
|
||||
masm.storeToTypedFloatArray(arrayType, maybeTempDouble, dest);
|
||||
} else {
|
||||
Register valueToStore = scratch2.ref();
|
||||
Register valueToStore = scratch2;
|
||||
if (arrayType == Scalar::Uint8Clamped) {
|
||||
if (!masm.clampConstantOrRegisterToUint8(cx_, val, maybeTempDouble, valueToStore,
|
||||
failure->label()))
|
||||
|
|
|
@ -3419,6 +3419,18 @@ LIRGenerator::visitStoreElement(MStoreElement* ins)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
BoundsCheckNeedsSpectreTemp()
|
||||
{
|
||||
// On x86, spectreBoundsCheck32 can emit better code if it has a scratch
|
||||
// register and index masking is enabled.
|
||||
#ifdef JS_CODEGEN_X86
|
||||
return JitOptions.spectreIndexMasking;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
||||
{
|
||||
|
@ -3429,16 +3441,19 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
|||
const LUse elements = useRegister(ins->elements());
|
||||
const LAllocation index = useRegister(ins->index());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
LInstruction* lir;
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()));
|
||||
lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()),
|
||||
spectreTemp);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
|
||||
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, spectreTemp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3457,14 +3472,18 @@ LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
|
|||
const LUse elements = useRegister(ins->elements());
|
||||
const LAllocation index = useRegister(ins->index());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
LInstruction* lir;
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()));
|
||||
lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
|
||||
spectreTemp);
|
||||
break;
|
||||
default:
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value);
|
||||
lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value,
|
||||
spectreTemp);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3563,10 +3582,13 @@ LIRGenerator::visitArrayPush(MArrayPush* ins)
|
|||
|
||||
LUse object = useRegister(ins->object());
|
||||
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
switch (ins->value()->type()) {
|
||||
case MIRType::Value:
|
||||
{
|
||||
LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp());
|
||||
LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp(),
|
||||
spectreTemp);
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
|
@ -3575,7 +3597,7 @@ LIRGenerator::visitArrayPush(MArrayPush* ins)
|
|||
default:
|
||||
{
|
||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp());
|
||||
LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp(), spectreTemp);
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
break;
|
||||
|
@ -3798,7 +3820,7 @@ LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins)
|
|||
else
|
||||
value = useRegisterOrNonDoubleConstant(ins->value());
|
||||
|
||||
LDefinition spectreTemp = JitOptions.spectreIndexMasking ? temp() : LDefinition::BogusTemp();
|
||||
LDefinition spectreTemp = BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
|
||||
auto* lir =
|
||||
new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value, spectreTemp);
|
||||
add(lir, ins);
|
||||
|
|
|
@ -6440,19 +6440,21 @@ class LStoreElementT : public LInstructionHelper<0, 3, 0>
|
|||
};
|
||||
|
||||
// Like LStoreElementV, but supports indexes >= initialized length.
|
||||
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
||||
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreElementHoleV)
|
||||
|
||||
LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LBoxAllocation& value)
|
||||
const LAllocation& index, const LBoxAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 3;
|
||||
|
@ -6469,22 +6471,27 @@ class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
|||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementT, but supports indexes >= initialized length.
|
||||
class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
|
||||
class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(StoreElementHoleT)
|
||||
|
||||
LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
|
||||
const LAllocation& index, const LAllocation& value)
|
||||
const LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
const MStoreElementHole* mir() const {
|
||||
|
@ -6502,22 +6509,27 @@ class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
|
|||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
||||
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 LAllocation& index, const LBoxAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 3;
|
||||
|
@ -6534,22 +6546,27 @@ class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
|||
const LAllocation* index() {
|
||||
return getOperand(2);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
|
||||
class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
|
||||
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 LAllocation& index, const LAllocation& value,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, elements);
|
||||
setOperand(2, index);
|
||||
setOperand(3, value);
|
||||
setTemp(0, spectreTemp);
|
||||
}
|
||||
|
||||
const MFallibleStoreElement* mir() const {
|
||||
|
@ -6567,6 +6584,9 @@ class LFallibleStoreElementT : public LInstructionHelper<0, 4, 0>
|
|||
const LAllocation* value() {
|
||||
return getOperand(3);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
|
||||
|
@ -6681,17 +6701,19 @@ class LArrayPopShiftT : public LInstructionHelper<1, 1, 2>
|
|||
}
|
||||
};
|
||||
|
||||
class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
|
||||
class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArrayPushV)
|
||||
|
||||
LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp)
|
||||
LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setBoxOperand(Value, value);
|
||||
setTemp(0, temp);
|
||||
setTemp(1, spectreTemp);
|
||||
}
|
||||
|
||||
static const size_t Value = 1;
|
||||
|
@ -6705,19 +6727,24 @@ class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
|
|||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(1);
|
||||
}
|
||||
};
|
||||
|
||||
class LArrayPushT : public LInstructionHelper<1, 2, 1>
|
||||
class LArrayPushT : public LInstructionHelper<1, 2, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArrayPushT)
|
||||
|
||||
LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp)
|
||||
LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp,
|
||||
const LDefinition& spectreTemp)
|
||||
: LInstructionHelper(classOpcode)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, value);
|
||||
setTemp(0, temp);
|
||||
setTemp(1, spectreTemp);
|
||||
}
|
||||
|
||||
const MArrayPush* mir() const {
|
||||
|
@ -6732,6 +6759,9 @@ class LArrayPushT : public LInstructionHelper<1, 2, 1>
|
|||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
const LDefinition* spectreTemp() {
|
||||
return getTemp(1);
|
||||
}
|
||||
};
|
||||
|
||||
class LArraySlice : public LCallInstructionHelper<1, 3, 2>
|
||||
|
|
Загрузка…
Ссылка в новой задаче