commit 84a64ae8b98b0530766adab9ed2a23ba86b8d644
parent d2c9637c107bd9e5c54a4d14ab598249daca97fb
Author: Alexandru Marc <amarc@mozilla.com>
Date: Fri, 12 Dec 2025 03:03:27 +0200
Revert "Bug 1999828: Part 7 - Add tests. r=iain" for causing bc failures at ScalarReplacement.cpp
This reverts commit 437712a9e466460933a4d854eacb4d2ec87d5053.
Revert "Bug 1999828: Part 6 - Implement StoreFixedSlotFromOffset and StoreDynamicSlotFromOffset. r=iain"
This reverts commit 374129481e266e1ed253d953ecee3182b20ac498.
Revert "Bug 1999828: Part 5 - Implement LoadFixedSlotFromOffset and LoadDynamicSlotFromOffset. r=iain"
This reverts commit 5e9c8f20bfc9abd501a9340ecfb16d4a58bd4065.
Revert "Bug 1999828: Part 4 - Implement GuardShapeListToOffset. r=iain"
This reverts commit 74a159492d658aa8964c2078f3abebccfc1ede06.
Revert "Bug 1999828: Part 3 - Implement GuardMultipleShapesToOffset. r=iain"
This reverts commit 1e3056aabe563607243f09c16028da94443f6f03.
Revert "Bug 1999828: Part 2 - Add additional stubfolding spew information. r=iain"
This reverts commit 9b4615ce61d33853b7cd054f0a11463a1a54aedd.
Revert "Bug 1999828: Part 1 - Split TryFoldingStubs into two passes. One to detect the shape (and later slot offset) and another to gather the values. r=iain"
This reverts commit b90c10909db17cd4d89c5ce56016fbf07a25f2f6.
Diffstat:
31 files changed, 235 insertions(+), 1774 deletions(-)
diff --git a/js/src/jit-test/tests/cacheir/guard-shape-to-offset-list.js b/js/src/jit-test/tests/cacheir/guard-shape-to-offset-list.js
@@ -1,28 +0,0 @@
-function test() {
- var n = 3;
- var arr = [];
- for (var i = 0; i < n; i++) {
- var obj = {};
- for (var j = 0; j < i+4; j++) {
- obj["x_" + i + "_" + j] = 1;
- }
- arr.push(obj);
- }
- for (var i = 0; i < n; i++) {
- arr[i].a = -1;
- arr[i].b = -1;
- }
-
- for (let i=0; i<10000; i++) {
- arr[i%n].a = 0;
- arr[i%n].b = 1;
- }
-
-
- for (var i = 0; i < n; i++) {
- assertEq(arr[i].a, 0);
- assertEq(arr[i].b, 1);
- }
-}
-
-test();
diff --git a/js/src/jit-test/tests/cacheir/ion-store-load-from-offset.js b/js/src/jit-test/tests/cacheir/ion-store-load-from-offset.js
@@ -1,58 +0,0 @@
-// |jit-test| --ion-offthread-compile=off;
-//
-function test(arr, max) {
-
- // LoadFixedFromOffset
- var test = 0;
- for (let i=0; i<20; i++) {
- test = arr[i%max].a;
- }
-
- // StoreFixedFromOffset
- var test = 0;
- for (let i=0; i<20; i++) {
- arr[i%max].a = i%max;
- }
-
- for (let i=0; i<max; i++) {
- assertEq(arr[i].a, i);
- }
-}
-
-var arr = [];
-arr[0] = {a:0};
-arr[1] = {b:0, a:1};
-arr[2] = {c:0, a:2};
-
-// GuardShapeListToOffset (3)
-for (let i=0; i<1000; i++) {
- test(arr, arr.length);
-}
-
-arr[3] = {d:0, a:3};
-
-// GuardShapeListToOffset (4)
-for (let i=0; i<1000; i++) {
- test(arr, arr.length);
-}
-
-arr[4] = {e:0, a:4};
-
-// GuardMultipleShapesToOffset (5)
-for (let i=0; i<1000; i++) {
- test(arr, arr.length);
-}
-
-arr[5] = {f:0, a:4};
-
-// GuardMultipleShapesToOffset (6)
-for (let i=0; i<1000; i++) {
- test(arr, arr.length);
-}
-
-arr[6] = {g:0, a:4};
-
-// GuardMultipleShapesToOffset (7)
-for (let i=0; i<1000; i++) {
- test(arr, arr.length);
-}
diff --git a/js/src/jit-test/tests/cacheir/ops-guard-shapelist-to-offset.js b/js/src/jit-test/tests/cacheir/ops-guard-shapelist-to-offset.js
@@ -1,37 +0,0 @@
-function test() {
- var arr = [];
- var num = 2;
- for (var i = 0; i < 20; i++) {
- var obj = {};
- for (var j = 0; j < i+4; j++) {
- obj["x_" + i + "_" + j] = 1;
- }
- arr.push(obj);
- }
- for (var i = 0; i < arr.length; i++) {
- arr[i].a = 0;
- arr[i].b = -i;
- }
-
- for (let i=0; i<10000; i++) {
- arr[i%num].a = i%num;
- }
-
- var t = 0;
- for (let i=0; i<10000; i++) {
- t = arr[i%num].a;
- }
-
- var t = 0;
- for (let i=0; i<10000; i++) {
- t = arr[i%num].a;
- t = arr[i%num].b;
- assertEq(t, -(i%num))
- }
-
- for (let i=0; i<num; i++) {
- assertEq(arr[i].a, i);
- }
-}
-
-test();
diff --git a/js/src/jit-test/tests/cacheir/ops-using-from-offset.js b/js/src/jit-test/tests/cacheir/ops-using-from-offset.js
@@ -1,29 +0,0 @@
-function test() {
- var arr = [];
- var num = 5;
- for (var i = 0; i < 20; i++) {
- var obj = {};
- for (var j = 0; j < i+4; j++) {
- obj["x_" + i + "_" + j] = 1;
- }
- arr.push(obj);
- }
- for (var i = 0; i < arr.length; i++) {
- arr[i].a = 0;
- }
-
- for (let i=0; i<10000; i++) {
- arr[i%num].a = i%num;
- }
-
- var t = 0;
- for (let i=0; i<10000; i++) {
- t = arr[i%num].a;
- }
-
- for (let i=0; i<num; i++) {
- assertEq(arr[i].a, i);
- }
-}
-
-test();
diff --git a/js/src/jit-test/tests/cacheir/stored-dynamic-slot-from-offset.js b/js/src/jit-test/tests/cacheir/stored-dynamic-slot-from-offset.js
@@ -1,34 +0,0 @@
-function test() {
- var arr = [];
- for (var i = 0; i < 20; i++) {
- var obj = {};
- for (var j = 0; j < i+4; j++) {
- obj["x_" + i + "_" + j] = 1;
- }
- arr.push(obj);
- }
- for (var i = 0; i < arr.length; i++) {
- arr[i].a = 0;
- }
-
- for (let i=0; i<10000; i++) {
- arr[i%9].a = i%9;
- }
-
- assertEq(arr[0].a, 0);
- assertEq(arr[1].a, 1);
- assertEq(arr[2].a, 2);
- assertEq(arr[3].a, 3);
- assertEq(arr[4].a, 4);
- assertEq(arr[5].a, 5);
- assertEq(arr[6].a, 6);
- assertEq(arr[7].a, 7);
- assertEq(arr[8].a, 8);
-
- for (let i=0; i<10000; i++) {
- var a = arr[i%9].a;
- assertEq(a, i%9);
- }
-}
-
-test();
diff --git a/js/src/jit-test/tests/cacheir/stored-fixed-slot-from-offset.js b/js/src/jit-test/tests/cacheir/stored-fixed-slot-from-offset.js
@@ -1,28 +0,0 @@
-function test() {
- var arr = [];
- arr[0] = {a:0};
- arr[1] = {b:0, a:0};
- arr[2] = {c:0, a:0};
- arr[3] = {d:0, a:0};
- arr[4] = {e:0, a:0};
- arr[5] = {f:0, a:0};
- arr[6] = {g:0, a:0};
- arr[7] = {h:0, a:0};
- arr[8] = {i:0, a:0};
-
- for (let i=0; i<10000; i++) {
- arr[i%9].a = ((i%9)==8)?2:1;
- }
-
- assertEq(arr[0].a, 1);
- assertEq(arr[1].a, 1);
- assertEq(arr[2].a, 1);
- assertEq(arr[3].a, 1);
- assertEq(arr[4].a, 1);
- assertEq(arr[5].a, 1);
- assertEq(arr[6].a, 1);
- assertEq(arr[7].a, 1);
- assertEq(arr[8].a, 2);
-}
-
-test();
diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h
@@ -81,8 +81,6 @@ class ValOperandId : public OperandId {
public:
ValOperandId() = default;
explicit ValOperandId(uint16_t id) : OperandId(id) {}
-
- bool operator==(const ValOperandId& other) const { return id_ == other.id_; }
};
class ValueTagOperandId : public OperandId {
diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
@@ -1478,26 +1478,19 @@ bool CacheIRWriter::stubDataEquals(const uint8_t* stubData) const {
return true;
}
-bool CacheIRWriter::stubDataEqualsIgnoringShapeAndOffset(
- const uint8_t* stubData, uint32_t shapeFieldOffset,
- mozilla::Maybe<uint32_t> offsetFieldOffset) const {
+bool CacheIRWriter::stubDataEqualsIgnoring(const uint8_t* stubData,
+ uint32_t ignoreOffset) const {
MOZ_ASSERT(!failed());
uint32_t offset = 0;
for (const StubField& field : stubFields_) {
- if (offset == shapeFieldOffset) {
- // Don't compare shapeField.
- } else if (offsetFieldOffset.isSome() && offset == *offsetFieldOffset) {
- // Skip offsetField, the "FromOffset" variant doesn't have this.
- continue;
- } else {
+ if (offset != ignoreOffset) {
if (field.sizeIsWord()) {
uintptr_t raw = *reinterpret_cast<const uintptr_t*>(stubData + offset);
if (field.asWord() != raw) {
return false;
}
} else {
- MOZ_ASSERT(field.sizeIsInt64());
uint64_t raw = *reinterpret_cast<const uint64_t*>(stubData + offset);
if (field.asInt64() != raw) {
return false;
@@ -2562,58 +2555,6 @@ bool CacheIRCompiler::emitLoadFixedSlot(ValOperandId resultId,
return true;
}
-bool CacheIRCompiler::emitLoadFixedSlotFromOffsetResult(
- ObjOperandId objId, Int32OperandId offsetId) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
- AutoOutputRegister output(*this);
- Register obj = allocator.useRegister(masm, objId);
- Register offset = allocator.useRegister(masm, offsetId);
-
- // Load the value at the offset reg.
- masm.loadValue(BaseIndex(obj, offset, TimesOne), output.valueReg());
- return true;
-}
-
-bool CacheIRCompiler::emitStoreFixedSlotFromOffset(ObjOperandId objId,
- Int32OperandId offsetId,
- ValOperandId rhsId) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-
- AutoScratchRegister scratch(allocator, masm);
- Register obj = allocator.useRegister(masm, objId);
- Register offset = allocator.useRegister(masm, offsetId);
- ValueOperand val = allocator.useValueRegister(masm, rhsId);
-
- BaseIndex slot(obj, offset, TimesOne);
- EmitPreBarrier(masm, slot, MIRType::Value);
-
- masm.storeValue(val, slot);
-
- emitPostBarrierSlot(obj, val, scratch);
-
- return true;
-}
-
-bool CacheIRCompiler::emitStoreDynamicSlotFromOffset(ObjOperandId objId,
- Int32OperandId offsetId,
- ValOperandId rhsId) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-
- Register obj = allocator.useRegister(masm, objId);
- Register offset = allocator.useRegister(masm, offsetId);
- ValueOperand val = allocator.useValueRegister(masm, rhsId);
-
- AutoScratchRegister slots(allocator, masm);
-
- masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), slots);
- BaseIndex slot(slots, offset, TimesOne);
- EmitPreBarrier(masm, slot, MIRType::Value);
- masm.storeValue(val, slot);
-
- emitPostBarrierSlot(obj, val, /*scratch=*/slots);
- return true;
-}
-
bool CacheIRCompiler::emitLoadDynamicSlot(ValOperandId resultId,
ObjOperandId objId,
uint32_t slotOffset) {
@@ -2632,20 +2573,6 @@ bool CacheIRCompiler::emitLoadDynamicSlot(ValOperandId resultId,
return true;
}
-bool CacheIRCompiler::emitLoadDynamicSlotFromOffsetResult(
- ObjOperandId objId, Int32OperandId offsetId) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
- AutoOutputRegister output(*this);
- Register obj = allocator.useRegister(masm, objId);
- Register offset = allocator.useRegister(masm, offsetId);
- AutoScratchRegister scratch(allocator, masm);
-
- // obj->slots
- masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
- masm.loadValue(BaseIndex(scratch, offset, TimesOne), output.valueReg());
- return true;
-}
-
bool CacheIRCompiler::emitGuardIsNativeObject(ObjOperandId objId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
@@ -9992,39 +9919,8 @@ bool CacheIRCompiler::emitGuardMultipleShapes(ObjOperandId objId,
emitLoadStubField(shapeArray, shapes);
masm.loadPtr(Address(shapes, NativeObject::offsetOfElements()), shapes);
- masm.branchTestObjShapeList(obj, shapes, scratch, scratch2, spectreScratch,
- failure->label());
- return true;
-}
-
-bool CacheIRCompiler::emitGuardMultipleShapesToOffset(ObjOperandId objId,
- uint32_t shapesOffset,
- Int32OperandId offsetId) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
- Register obj = allocator.useRegister(masm, objId);
- Register offset = allocator.defineRegister(masm, offsetId);
- AutoScratchRegister shapes(allocator, masm);
- AutoScratchRegister scratch(allocator, masm);
- AutoScratchRegister scratch2(allocator, masm);
-
- bool needSpectreMitigations = objectGuardNeedsSpectreMitigations(objId);
-
- // We can re-use the output (offset) as scratch spectre register,
- // since the output is only set after all branches.
- Register spectreScratch = needSpectreMitigations ? offset : InvalidReg;
-
- FailurePath* failure;
- if (!addFailurePath(&failure)) {
- return false;
- }
-
- // The stub field contains a ListObject. Load its elements.
- StubFieldOffset shapeArray(shapesOffset, StubField::Type::JSObject);
- emitLoadStubField(shapeArray, shapes);
- masm.loadPtr(Address(shapes, NativeObject::offsetOfElements()), shapes);
-
- masm.branchTestObjShapeListSetOffset(obj, shapes, offset, scratch, scratch2,
- spectreScratch, failure->label());
+ masm.branchTestObjShapeList(Assembler::NotEqual, obj, shapes, scratch,
+ scratch2, spectreScratch, failure->label());
return true;
}
diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml
@@ -248,16 +248,6 @@
obj: ObjId
shapes: ObjectField
-- name: GuardMultipleShapesToOffset
- shared: true
- transpile: true
- cost_estimate: 2
- custom_writer: true
- args:
- obj: ObjId
- shapes: ObjectField
- result: Int32Id
-
- name: GuardProto
shared: false
transpile: true
@@ -806,32 +796,6 @@
obj: ObjId
offset: RawInt32Field
-- name: LoadFixedSlotFromOffsetResult
- shared: true
- transpile: true
- cost_estimate: 2
- args:
- obj: ObjId
- offset: Int32Id
-
-- name: StoreFixedSlotFromOffset
- shared: true
- transpile: true
- cost_estimate: 6
- args:
- obj: ObjId
- offset: Int32Id
- rhs: ValId
-
-- name: StoreDynamicSlotFromOffset
- shared: true
- transpile: true
- cost_estimate: 6
- args:
- obj: ObjId
- offset: Int32Id
- rhs: ValId
-
- name: LoadDynamicSlot
shared: true
transpile: true
@@ -841,14 +805,6 @@
obj: ObjId
slot: RawInt32Field
-- name: LoadDynamicSlotFromOffsetResult
- shared: true
- transpile: true
- cost_estimate: 2
- args:
- obj: ObjId
- offset: Int32Id
-
- name: GuardNoAllocationMetadataBuilder
shared: true
transpile: true
diff --git a/js/src/jit/CacheIRWriter.h b/js/src/jit/CacheIRWriter.h
@@ -393,9 +393,8 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
size_t stubDataSize() const { return stubDataSize_; }
void copyStubData(uint8_t* dest) const;
bool stubDataEquals(const uint8_t* stubData) const;
- bool stubDataEqualsIgnoringShapeAndOffset(
- const uint8_t* stubData, uint32_t shapeFieldOffset,
- mozilla::Maybe<uint32_t> offsetFieldOffset) const;
+ bool stubDataEqualsIgnoring(const uint8_t* stubData,
+ uint32_t ignoreOffset) const;
bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
if (operandId >= operandLastUsed_.length()) {
@@ -730,12 +729,6 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
guardMultipleShapes_(obj, shapes);
}
- Int32OperandId guardMultipleShapesToOffset(ObjOperandId obj,
- ListObject* shapes) {
- MOZ_ASSERT(shapes->length() > 0);
- return guardMultipleShapesToOffset_(obj, shapes);
- }
-
friend class CacheIRCloner;
CACHE_IR_WRITER_GENERATED
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
@@ -4300,16 +4300,6 @@ void CodeGenerator::visitLoadDynamicSlotV(LLoadDynamicSlotV* lir) {
masm.loadValue(Address(base, offset), dest);
}
-void CodeGenerator::visitLoadDynamicSlotFromOffset(
- LLoadDynamicSlotFromOffset* lir) {
- ValueOperand dest = ToOutValue(lir);
- Register slots = ToRegister(lir->slots());
- Register offset = ToRegister(lir->offset());
-
- // slots[offset]
- masm.loadValue(BaseIndex(slots, offset, TimesOne), dest);
-}
-
static ConstantOrRegister ToConstantOrRegister(const LAllocation* value,
MIRType valueType) {
if (value->isConstant()) {
@@ -4345,47 +4335,6 @@ void CodeGenerator::visitStoreDynamicSlotV(LStoreDynamicSlotV* lir) {
masm.storeValue(value, Address(base, offset));
}
-void CodeGenerator::visitStoreDynamicSlotFromOffsetV(
- LStoreDynamicSlotFromOffsetV* lir) {
- Register slots = ToRegister(lir->slots());
- Register offset = ToRegister(lir->offset());
- ValueOperand value = ToValue(lir->value());
- Register temp = ToRegister(lir->temp0());
-
- BaseIndex baseIndex(slots, offset, TimesOne);
- masm.computeEffectiveAddress(baseIndex, temp);
-
- Address address(temp, 0);
-
- emitPreBarrier(address);
-
- // obj->slots[offset]
- masm.storeValue(value, address);
-}
-
-void CodeGenerator::visitStoreDynamicSlotFromOffsetT(
- LStoreDynamicSlotFromOffsetT* lir) {
- Register slots = ToRegister(lir->slots());
- Register offset = ToRegister(lir->offset());
- const LAllocation* value = lir->value();
- MIRType valueType = lir->mir()->value()->type();
- Register temp = ToRegister(lir->temp0());
-
- BaseIndex baseIndex(slots, offset, TimesOne);
- masm.computeEffectiveAddress(baseIndex, temp);
-
- Address address(temp, 0);
-
- emitPreBarrier(address);
-
- // obj->slots[offset]
- ConstantOrRegister nvalue =
- value->isConstant()
- ? ConstantOrRegister(value->toConstant()->toJSValue())
- : TypedOrValueRegister(valueType, ToAnyRegister(value));
- masm.storeConstantOrRegister(nvalue, address);
-}
-
void CodeGenerator::visitElements(LElements* lir) {
Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
masm.loadPtr(elements, ToRegister(lir->output()));
@@ -4547,7 +4496,8 @@ void CodeGenerator::visitGuardMultipleShapes(LGuardMultipleShapes* guard) {
Label bail;
masm.loadPtr(Address(shapeList, NativeObject::offsetOfElements()), temp);
- masm.branchTestObjShapeList(obj, temp, temp2, temp3, spectre, &bail);
+ masm.branchTestObjShapeList(Assembler::NotEqual, obj, temp, temp2, temp3,
+ spectre, &bail);
bailoutFrom(&bail, guard->snapshot());
}
@@ -4589,73 +4539,6 @@ void CodeGenerator::visitGuardShapeList(LGuardShapeList* guard) {
bailoutFrom(&bail, guard->snapshot());
}
-void CodeGenerator::visitGuardShapeListToOffset(
- LGuardShapeListToOffset* guard) {
- Register obj = ToRegister(guard->object());
- Register temp = ToRegister(guard->temp0());
- Register spectre = ToTempRegisterOrInvalid(guard->temp1());
- Register offset = ToRegister(guard->output());
-
- Label done, bail;
- masm.loadObjShapeUnsafe(obj, temp);
-
- // Count the number of branches to emit.
- const auto& shapes = guard->mir()->shapeList()->shapes();
- const auto& offsets = guard->mir()->shapeList()->offsets();
- size_t branchesLeft = std::count_if(shapes.begin(), shapes.end(),
- [](Shape* s) { return s != nullptr; });
- MOZ_RELEASE_ASSERT(branchesLeft > 0);
-
- size_t index = 0;
- for (Shape* shape : shapes) {
- if (!shape) {
- index++;
- continue;
- }
-
- if (branchesLeft > 1) {
- Label next;
- masm.branchPtr(Assembler::NotEqual, temp, ImmGCPtr(shape), &next);
- if (spectre != InvalidReg) {
- masm.spectreMovePtr(Assembler::NotEqual, spectre, obj);
- }
- masm.move32(Imm32(offsets[index]), offset);
- masm.jump(&done);
- masm.bind(&next);
- } else {
- masm.branchPtr(Assembler::NotEqual, temp, ImmGCPtr(shape), &bail);
- if (spectre != InvalidReg) {
- masm.spectreMovePtr(Assembler::NotEqual, spectre, obj);
- }
- masm.move32(Imm32(offsets[index]), offset);
- }
-
- branchesLeft--;
- index++;
- }
- MOZ_ASSERT(branchesLeft == 0);
-
- masm.bind(&done);
- bailoutFrom(&bail, guard->snapshot());
-}
-
-void CodeGenerator::visitGuardMultipleShapesToOffset(
- LGuardMultipleShapesToOffset* guard) {
- Register obj = ToRegister(guard->object());
- Register shapeList = ToRegister(guard->shapeList());
- Register temp = ToRegister(guard->temp0());
- Register temp1 = ToRegister(guard->temp1());
- Register temp2 = ToRegister(guard->temp2());
- Register offset = ToRegister(guard->output());
- Register spectre = JitOptions.spectreObjectMitigations ? offset : InvalidReg;
-
- Label bail;
- masm.loadPtr(Address(shapeList, NativeObject::offsetOfElements()), temp);
- masm.branchTestObjShapeListSetOffset(obj, temp, offset, temp1, temp2, spectre,
- &bail);
- bailoutFrom(&bail, guard->snapshot());
-}
-
void CodeGenerator::visitGuardProto(LGuardProto* guard) {
Register obj = ToRegister(guard->object());
Register expected = ToRegister(guard->expected());
@@ -18042,59 +17925,6 @@ void CodeGenerator::visitLoadFixedSlotT(LLoadFixedSlotT* ins) {
type, result);
}
-void CodeGenerator::visitLoadFixedSlotFromOffset(
- LLoadFixedSlotFromOffset* lir) {
- Register obj = ToRegister(lir->object());
- Register offset = ToRegister(lir->offset());
- ValueOperand out = ToOutValue(lir);
-
- // obj[offset]
- masm.loadValue(BaseIndex(obj, offset, TimesOne), out);
-}
-
-void CodeGenerator::visitStoreFixedSlotFromOffsetV(
- LStoreFixedSlotFromOffsetV* lir) {
- Register obj = ToRegister(lir->object());
- Register offset = ToRegister(lir->offset());
- ValueOperand value = ToValue(lir->value());
- Register temp = ToRegister(lir->temp0());
-
- BaseIndex baseIndex(obj, offset, TimesOne);
- masm.computeEffectiveAddress(baseIndex, temp);
-
- Address slot(temp, 0);
- if (lir->mir()->needsBarrier()) {
- emitPreBarrier(slot);
- }
-
- // obj[offset]
- masm.storeValue(value, slot);
-}
-
-void CodeGenerator::visitStoreFixedSlotFromOffsetT(
- LStoreFixedSlotFromOffsetT* lir) {
- Register obj = ToRegister(lir->object());
- Register offset = ToRegister(lir->offset());
- const LAllocation* value = lir->value();
- MIRType valueType = lir->mir()->value()->type();
- Register temp = ToRegister(lir->temp0());
-
- BaseIndex baseIndex(obj, offset, TimesOne);
- masm.computeEffectiveAddress(baseIndex, temp);
-
- Address slot(temp, 0);
- if (lir->mir()->needsBarrier()) {
- emitPreBarrier(slot);
- }
-
- // obj[offset]
- ConstantOrRegister nvalue =
- value->isConstant()
- ? ConstantOrRegister(value->toConstant()->toJSValue())
- : TypedOrValueRegister(valueType, ToAnyRegister(value));
- masm.storeConstantOrRegister(nvalue, slot);
-}
-
template <typename T>
static void EmitLoadAndUnbox(MacroAssembler& masm, const T& src, MIRType type,
bool fallible, AnyRegister dest, Register64 temp,
diff --git a/js/src/jit/GenerateMIRFiles.py b/js/src/jit/GenerateMIRFiles.py
@@ -59,8 +59,6 @@ type_policies = {
"Double": "DoublePolicy",
"String": "StringPolicy",
"Symbol": "SymbolPolicy",
- "NoTypePolicy": "NoTypePolicy",
- "Slots": "NoTypePolicy",
}
@@ -68,22 +66,16 @@ def decide_type_policy(types, no_type_policy):
if no_type_policy:
return "public NoTypePolicy::Data"
+ if len(types) == 1:
+ return f"public {type_policies[types[0]]}<0>::Data"
+
type_num = 0
mixed_type_policies = []
for mir_type in types:
policy = type_policies[mir_type]
- if policy == "NoTypePolicy":
- type_num += 1
- continue
mixed_type_policies.append(f"{policy}<{type_num}>")
type_num += 1
- if len(mixed_type_policies) == 0:
- return "public NoTypePolicy::Data"
-
- if len(mixed_type_policies) == 1:
- return f"public {mixed_type_policies[0]}::Data"
-
return "public MixPolicy<{}>::Data".format(", ".join(mixed_type_policies))
diff --git a/js/src/jit/JitScript.cpp b/js/src/jit/JitScript.cpp
@@ -1024,22 +1024,6 @@ HashNumber ICScript::hash(JSContext* cx) {
}
break;
}
- case CacheOp::GuardMultipleShapesToOffset: {
- auto args = reader.argsForGuardMultipleShapesToOffset();
- JSObject* shapes =
- stubInfo->getStubField<StubField::Type::JSObject>(
- stub->toCacheIRStub(), args.shapesOffset);
- auto* shapesObject = &shapes->as<ShapeListWithOffsetsObject>();
- size_t numShapes = shapesObject->numShapes();
- if (ShapeListSnapshot::shouldSnapshot(numShapes)) {
- for (size_t i = 0; i < numShapes; i++) {
- Shape* shape = shapesObject->getShapeUnbarriered(i);
- h = mozilla::AddToHash(h, shape);
- h = mozilla::AddToHash(h, shapesObject->getOffset(i));
- }
- }
- break;
- }
default:
reader.skip(CacheIROpInfos[size_t(op)].argLength);
break;
diff --git a/js/src/jit/JitSpewer.cpp b/js/src/jit/JitSpewer.cpp
@@ -338,8 +338,6 @@ static void PrintHelpAndExit(int status = 0) {
" gcbarriers Redundant GC barrier elimination\n"
" loadkeys Loads used as property keys\n"
" stubfolding CacheIR stub folding\n"
- " stubfolding-details Same as stubfolding, but with spewing of stub "
- "content.\n"
" logs JSON visualization logging\n"
" logs-sync Same as logs, but flushes between each pass (sync. "
"compiled functions only).\n"
@@ -448,9 +446,6 @@ void jit::CheckLogging() {
EnableChannel(JitSpew_MarkLoadsUsedAsPropertyKeys);
} else if (IsFlag(found, "stubfolding")) {
EnableChannel(JitSpew_StubFolding);
- } else if (IsFlag(found, "stubfolding-details")) {
- EnableChannel(JitSpew_StubFolding);
- EnableChannel(JitSpew_StubFoldingDetails);
} else if (IsFlag(found, "logs")) {
EnableIonDebugAsyncLogging();
} else if (IsFlag(found, "logs-sync")) {
diff --git a/js/src/jit/JitSpewer.h b/js/src/jit/JitSpewer.h
@@ -24,107 +24,105 @@ namespace js {
namespace jit {
// New channels may be added below.
-#define JITSPEW_CHANNEL_LIST(_) \
- /* Information during sinking */ \
- _(Prune) \
- /* Information during escape analysis */ \
- _(Escape) \
- /* Information during alias analysis */ \
- _(Alias) \
- /* Information during alias analysis */ \
- _(AliasSummaries) \
- /* Information during GVN */ \
- _(GVN) \
- /* Information during sinking */ \
- _(Sink) \
- /* Information during Range analysis */ \
- _(Range) \
- /* Information during LICM */ \
- _(LICM) \
- /* Information during Branch Hinting */ \
- _(BranchHint) \
- /* Info about fold linear constants */ \
- _(FLAC) \
- /* Effective address analysis info */ \
- _(EAA) \
- /* Wasm Bounds Check Elimination */ \
- _(WasmBCE) \
- /* Information during regalloc */ \
- _(RegAlloc) \
- /* Information during inlining */ \
- _(Inlining) \
- /* Information during codegen */ \
- _(Codegen) \
- /* Debug info about safepoints */ \
- _(Safepoints) \
- /* Debug info about Pools*/ \
- _(Pools) \
- /* Profiling-related information */ \
- _(Profiling) \
- /* Debug info about the I$ */ \
- _(CacheFlush) \
- /* Info about redundant shape guards */ \
- _(RedundantShapeGuards) \
- /* Info about redundant GC barriers */ \
- _(RedundantGCBarriers) \
- /* Info about loads used as keys */ \
- _(MarkLoadsUsedAsPropertyKeys) \
- /* Output a list of MIR expressions */ \
- _(MIRExpressions) \
- /* Summary info about loop unrolling */ \
- _(Unroll) \
- /* Detailed info about loop unrolling */ \
- _(UnrollDetails) \
- /* Information about stub folding */ \
- _(StubFolding) \
- /* Additional information about stub folding */ \
- _(StubFoldingDetails) \
- \
- /* BASELINE COMPILER SPEW */ \
- \
- /* Aborting Script Compilation. */ \
- _(BaselineAbort) \
- /* Script Compilation. */ \
- _(BaselineScripts) \
- /* Detailed op-specific spew. */ \
- _(BaselineOp) \
- /* Inline caches. */ \
- _(BaselineIC) \
- /* Inline cache fallbacks. */ \
- _(BaselineICFallback) \
- /* OSR from Baseline => Ion. */ \
- _(BaselineOSR) \
- /* Bailouts. */ \
- _(BaselineBailouts) \
- /* Debug Mode On Stack Recompile . */ \
- _(BaselineDebugModeOSR) \
- \
- /* ION COMPILER SPEW */ \
- \
- /* Used to abort SSA construction */ \
- _(IonAbort) \
- /* Information about compiled scripts */ \
- _(IonScripts) \
- /* Info about failing to log script */ \
- _(IonSyncLogs) \
- /* Information during MIR building */ \
- _(IonMIR) \
- /* Information during bailouts */ \
- _(IonBailouts) \
- /* Information during OSI */ \
- _(IonInvalidate) \
- /* Debug info about snapshots */ \
- _(IonSnapshots) \
- /* Generated inline cache stubs */ \
- _(IonIC) \
- \
- /* WARP SPEW */ \
- \
- /* Generated WarpSnapshots */ \
- _(WarpSnapshots) \
- /* CacheIR transpiler logging */ \
- _(WarpTranspiler) \
- /* Trial inlining for Warp */ \
+#define JITSPEW_CHANNEL_LIST(_) \
+ /* Information during sinking */ \
+ _(Prune) \
+ /* Information during escape analysis */ \
+ _(Escape) \
+ /* Information during alias analysis */ \
+ _(Alias) \
+ /* Information during alias analysis */ \
+ _(AliasSummaries) \
+ /* Information during GVN */ \
+ _(GVN) \
+ /* Information during sinking */ \
+ _(Sink) \
+ /* Information during Range analysis */ \
+ _(Range) \
+ /* Information during LICM */ \
+ _(LICM) \
+ /* Information during Branch Hinting */ \
+ _(BranchHint) \
+ /* Info about fold linear constants */ \
+ _(FLAC) \
+ /* Effective address analysis info */ \
+ _(EAA) \
+ /* Wasm Bounds Check Elimination */ \
+ _(WasmBCE) \
+ /* Information during regalloc */ \
+ _(RegAlloc) \
+ /* Information during inlining */ \
+ _(Inlining) \
+ /* Information during codegen */ \
+ _(Codegen) \
+ /* Debug info about safepoints */ \
+ _(Safepoints) \
+ /* Debug info about Pools*/ \
+ _(Pools) \
+ /* Profiling-related information */ \
+ _(Profiling) \
+ /* Debug info about the I$ */ \
+ _(CacheFlush) \
+ /* Info about redundant shape guards */ \
+ _(RedundantShapeGuards) \
+ /* Info about redundant GC barriers */ \
+ _(RedundantGCBarriers) \
+ /* Info about loads used as keys */ \
+ _(MarkLoadsUsedAsPropertyKeys) \
+ /* Output a list of MIR expressions */ \
+ _(MIRExpressions) \
+ /* Summary info about loop unrolling */ \
+ _(Unroll) \
+ /* Detailed info about loop unrolling */ \
+ _(UnrollDetails) \
+ /* Information about stub folding */ \
+ _(StubFolding) \
+ \
+ /* BASELINE COMPILER SPEW */ \
+ \
+ /* Aborting Script Compilation. */ \
+ _(BaselineAbort) \
+ /* Script Compilation. */ \
+ _(BaselineScripts) \
+ /* Detailed op-specific spew. */ \
+ _(BaselineOp) \
+ /* Inline caches. */ \
+ _(BaselineIC) \
+ /* Inline cache fallbacks. */ \
+ _(BaselineICFallback) \
+ /* OSR from Baseline => Ion. */ \
+ _(BaselineOSR) \
+ /* Bailouts. */ \
+ _(BaselineBailouts) \
+ /* Debug Mode On Stack Recompile . */ \
+ _(BaselineDebugModeOSR) \
+ \
+ /* ION COMPILER SPEW */ \
+ \
+ /* Used to abort SSA construction */ \
+ _(IonAbort) \
+ /* Information about compiled scripts */ \
+ _(IonScripts) \
+ /* Info about failing to log script */ \
+ _(IonSyncLogs) \
+ /* Information during MIR building */ \
+ _(IonMIR) \
+ /* Information during bailouts */ \
+ _(IonBailouts) \
+ /* Information during OSI */ \
+ _(IonInvalidate) \
+ /* Debug info about snapshots */ \
+ _(IonSnapshots) \
+ /* Generated inline cache stubs */ \
+ _(IonIC) \
+ \
+ /* WARP SPEW */ \
+ \
+ /* Generated WarpSnapshots */ \
+ _(WarpSnapshots) \
+ /* CacheIR transpiler logging */ \
+ _(WarpTranspiler) \
+ /* Trial inlining for Warp */ \
_(WarpTrialInlining)
enum JitSpewChannel {
diff --git a/js/src/jit/LIROps.yaml b/js/src/jit/LIROps.yaml
@@ -2598,22 +2598,6 @@
value: WordSized
mir_op: StoreFixedSlot
-- name: StoreFixedSlotFromOffsetV
- operands:
- object: WordSized
- offset: WordSized
- value: BoxedValue
- num_temps: 1
- mir_op: StoreFixedSlotFromOffset
-
-- name: StoreFixedSlotFromOffsetT
- operands:
- object: WordSized
- offset: WordSized
- value: WordSized
- num_temps: 1
- mir_op: StoreFixedSlotFromOffset
-
- name: GetPropSuperCache
result_type: BoxedValue
operands:
@@ -2666,22 +2650,6 @@
value: WordSized
mir_op: StoreDynamicSlot
-- name: StoreDynamicSlotFromOffsetV
- operands:
- slots: WordSized
- offset: WordSized
- value: BoxedValue
- num_temps: 1
- mir_op: StoreDynamicSlotFromOffset
-
-- name: StoreDynamicSlotFromOffsetT
- operands:
- slots: WordSized
- offset: WordSized
- value: WordSized
- num_temps: 1
- mir_op: StoreDynamicSlotFromOffset
-
# Take the floor of a double precision number and converts it to an int32.
# Implements Math.floor().
- name: Floor
@@ -3066,14 +3034,6 @@
num: WordSized
mir_op: true
-- name: GuardMultipleShapesToOffset
- result_type: WordSized
- operands:
- object: WordSized
- shapeList: WordSized
- num_temps: 3
- mir_op: true
-
- name: GuardProto
operands:
object: WordSized
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
@@ -4207,15 +4207,6 @@ void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
}
}
-void LIRGenerator::visitLoadDynamicSlotFromOffset(
- MLoadDynamicSlotFromOffset* ins) {
- MOZ_ASSERT(ins->slots()->type() == MIRType::Slots);
-
- auto* lir = new (alloc()) LLoadDynamicSlotFromOffset(
- useRegisterAtStart(ins->slots()), useRegisterAtStart(ins->offset()));
- defineBox(lir, ins);
-}
-
void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
define(new (alloc())
LFunctionEnvironment(useRegisterAtStart(ins->function())),
@@ -5505,16 +5496,6 @@ void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
}
}
-void LIRGenerator::visitLoadFixedSlotFromOffset(MLoadFixedSlotFromOffset* ins) {
- MDefinition* obj = ins->object();
- MOZ_ASSERT(obj->type() == MIRType::Object);
- MOZ_ASSERT(ins->type() == MIRType::Value);
-
- auto* lir = new (alloc()) LLoadFixedSlotFromOffset(
- useRegisterAtStart(obj), useRegisterAtStart(ins->offset()));
- defineBox(lir, ins);
-}
-
void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
MDefinition* obj = ins->object();
MOZ_ASSERT(obj->type() == MIRType::Object);
@@ -5639,40 +5620,6 @@ void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
}
}
-void LIRGenerator::visitStoreFixedSlotFromOffset(
- MStoreFixedSlotFromOffset* ins) {
- MOZ_ASSERT(ins->object()->type() == MIRType::Object);
-
- if (ins->value()->type() == MIRType::Value) {
- LStoreFixedSlotFromOffsetV* lir = new (alloc()) LStoreFixedSlotFromOffsetV(
- useRegister(ins->object()), useRegister(ins->offset()),
- useBox(ins->value()), temp());
- add(lir, ins);
- } else {
- LStoreFixedSlotFromOffsetT* lir = new (alloc()) LStoreFixedSlotFromOffsetT(
- useRegister(ins->object()), useRegister(ins->offset()),
- useRegisterOrConstant(ins->value()), temp());
- add(lir, ins);
- }
-}
-
-void LIRGenerator::visitStoreDynamicSlotFromOffset(
- MStoreDynamicSlotFromOffset* ins) {
- MOZ_ASSERT(ins->slots()->type() == MIRType::Slots);
-
- if (ins->value()->type() == MIRType::Value) {
- auto* lir = new (alloc()) LStoreDynamicSlotFromOffsetV(
- useRegister(ins->slots()), useRegister(ins->offset()),
- useBox(ins->value()), temp());
- add(lir, ins);
- } else {
- auto* lir = new (alloc()) LStoreDynamicSlotFromOffsetT(
- useRegister(ins->slots()), useRegister(ins->offset()),
- useRegisterOrConstant(ins->value()), temp());
- add(lir, ins);
- }
-}
-
void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
@@ -5878,33 +5825,6 @@ void LIRGenerator::visitGuardShapeList(MGuardShapeList* ins) {
}
}
-void LIRGenerator::visitGuardShapeListToOffset(MGuardShapeListToOffset* ins) {
- MOZ_ASSERT(ins->object()->type() == MIRType::Object);
-
- if (JitOptions.spectreObjectMitigations) {
- auto* lir = new (alloc())
- LGuardShapeListToOffset(useRegister(ins->object()), temp(), temp());
- assignSnapshot(lir, ins->bailoutKind());
- define(lir, ins);
- } else {
- auto* lir = new (alloc()) LGuardShapeListToOffset(
- useRegister(ins->object()), temp(), LDefinition::BogusTemp());
- assignSnapshot(lir, ins->bailoutKind());
- define(lir, ins);
- }
-}
-
-void LIRGenerator::visitGuardMultipleShapesToOffset(
- MGuardMultipleShapesToOffset* ins) {
- MOZ_ASSERT(ins->object()->type() == MIRType::Object);
-
- auto* lir = new (alloc()) LGuardMultipleShapesToOffset(
- useRegister(ins->object()), useRegister(ins->shapeList()), temp(), temp(),
- temp());
- assignSnapshot(lir, ins->bailoutKind());
- define(lir, ins);
-}
-
void LIRGenerator::visitGuardProto(MGuardProto* ins) {
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
@@ -570,14 +570,6 @@ const MDefinition* MDefinition::skipObjectGuards() const {
result = result->toGuardMultipleShapes()->object();
continue;
}
- if (result->isGuardShapeListToOffset()) {
- result = result->toGuardShapeListToOffset()->object();
- continue;
- }
- if (result->isGuardMultipleShapesToOffset()) {
- result = result->toGuardMultipleShapesToOffset()->object();
- continue;
- }
if (result->isGuardNullProto()) {
result = result->toGuardNullProto()->object();
continue;
@@ -7233,28 +7225,6 @@ AliasSet MGuardShapeList::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
-bool MGuardShapeListToOffset::congruentTo(const MDefinition* ins) const {
- if (!congruentIfOperandsEqual(ins)) {
- return false;
- }
-
- const auto& shapesA = this->shapeList()->shapes();
- const auto& shapesB = ins->toGuardShapeListToOffset()->shapeList()->shapes();
- if (!std::equal(shapesA.begin(), shapesA.end(), shapesB.begin(),
- shapesB.end()))
- return false;
-
- const auto& offsetsA = this->shapeList()->offsets();
- const auto& offsetsB =
- ins->toGuardShapeListToOffset()->shapeList()->offsets();
- return std::equal(offsetsA.begin(), offsetsA.end(), offsetsB.begin(),
- offsetsB.end());
-}
-
-AliasSet MGuardShapeListToOffset::getAliasSet() const {
- return AliasSet::Load(AliasSet::ObjectFields);
-}
-
bool MHasShape::congruentTo(const MDefinition* ins) const {
if (!ins->isHasShape()) {
return false;
@@ -7337,19 +7307,6 @@ AliasSet MGuardMultipleShapes::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
-AliasSet MGuardMultipleShapesToOffset::getAliasSet() const {
- return AliasSet::Load(AliasSet::ObjectFields);
-}
-
-AliasSet MLoadFixedSlotFromOffset::getAliasSet() const {
- return AliasSet::Load(AliasSet::FixedSlot);
-}
-
-AliasSet MLoadDynamicSlotFromOffset::getAliasSet() const {
- MOZ_ASSERT(slots()->type() == MIRType::Slots);
- return AliasSet::Load(AliasSet::DynamicSlot);
-}
-
AliasSet MGuardGlobalGeneration::getAliasSet() const {
return AliasSet::Load(AliasSet::GlobalGenerationCounter);
}
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
@@ -75,7 +75,6 @@ namespace jit {
class CallInfo;
class ShapeListSnapshot;
-class ShapeListWithOffsetsSnapshot;
#ifdef JS_JITSPEW
// Helper for debug printing. Avoids creating a MIR.h <--> MIRGraph.h cycle.
@@ -7962,41 +7961,6 @@ class MStoreFixedSlot
ALLOW_CLONE(MStoreFixedSlot)
};
-class MStoreFixedSlotFromOffset
- : public MTernaryInstruction,
- public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>,
- NoFloatPolicy<2>>::Data {
- bool needsBarrier_;
-
- MStoreFixedSlotFromOffset(MDefinition* obj, MDefinition* offset,
- MDefinition* rval, bool barrier)
- : MTernaryInstruction(classOpcode, obj, offset, rval),
- needsBarrier_(barrier) {
- MOZ_ASSERT(obj->type() == MIRType::Object);
- }
-
- public:
- INSTRUCTION_HEADER(StoreFixedSlotFromOffset)
- NAMED_OPERANDS((0, object), (1, offset), (2, value))
-
- static MStoreFixedSlotFromOffset* NewBarriered(TempAllocator& alloc,
- MDefinition* obj,
- MDefinition* offset,
- MDefinition* rval) {
- return new (alloc) MStoreFixedSlotFromOffset(obj, offset, rval, true);
- }
-
- AliasSet getAliasSet() const override {
- return AliasSet::Store(AliasSet::FixedSlot);
- }
- bool needsBarrier() const { return needsBarrier_; }
- void setNeedsBarrier(bool needsBarrier = true) {
- needsBarrier_ = needsBarrier;
- }
-
- ALLOW_CLONE(MStoreFixedSlotFromOffset)
-};
-
class MGetPropertyCache : public MBinaryInstruction,
public MixPolicy<BoxExceptPolicy<0, MIRType::Object>,
CacheIdPolicy<1>>::Data {
@@ -8429,33 +8393,6 @@ class MStoreDynamicSlot : public MBinaryInstruction,
ALLOW_CLONE(MStoreDynamicSlot)
};
-class MStoreDynamicSlotFromOffset
- : public MTernaryInstruction,
- public MixPolicy<UnboxedInt32Policy<1>, NoFloatPolicy<2>>::Data {
- MStoreDynamicSlotFromOffset(MDefinition* slots, MDefinition* offset,
- MDefinition* rval, bool barrier)
- : MTernaryInstruction(classOpcode, slots, offset, rval) {
- MOZ_ASSERT(slots->type() == MIRType::Slots);
- }
-
- public:
- INSTRUCTION_HEADER(StoreDynamicSlotFromOffset)
- NAMED_OPERANDS((0, slots), (1, offset), (2, value))
-
- static MStoreDynamicSlotFromOffset* New(TempAllocator& alloc,
- MDefinition* slots,
- MDefinition* offset,
- MDefinition* rval) {
- return new (alloc) MStoreDynamicSlotFromOffset(slots, offset, rval, true);
- }
-
- AliasSet getAliasSet() const override {
- return AliasSet::Store(AliasSet::DynamicSlot);
- }
-
- ALLOW_CLONE(MStoreDynamicSlotFromOffset)
-};
-
class MSetPropertyCache : public MTernaryInstruction,
public MixPolicy<SingleObjectPolicy, CacheIdPolicy<1>,
NoFloatPolicy<2>>::Data {
diff --git a/js/src/jit/MIROps.yaml b/js/src/jit/MIROps.yaml
@@ -2130,16 +2130,6 @@
- name: LoadFixedSlot
gen_boilerplate: false
-- name: LoadFixedSlotFromOffset
- operands:
- object: Object
- offset: Int32
- result_type: Value
- movable: true
- congruent_to: if_operands_equal
- alias_set: custom
- generate_lir: true
-
- name: LoadFixedSlotAndUnbox
gen_boilerplate: false
@@ -2149,12 +2139,6 @@
- name: StoreFixedSlot
gen_boilerplate: false
-- name: StoreFixedSlotFromOffset
- gen_boilerplate: false
-
-- name: StoreDynamicSlotFromOffset
- gen_boilerplate: false
-
- name: GetPropertyCache
gen_boilerplate: false
@@ -2254,29 +2238,6 @@
generate_lir: true
lir_temps: 2
-- name: GuardShapeListToOffset
- operands:
- object: Object
- arguments:
- shapeList: const ShapeListWithOffsetsSnapshot*
- result_type: Int32
- guard: true
- movable: true
- congruent_to: custom
- alias_set: custom
- generate_lir: true
- lir_temps: 2
-
-- name: GuardMultipleShapesToOffset
- operands:
- object: Object
- shapeList: Object
- result_type: Int32
- guard: true
- movable: true
- congruent_to: if_operands_equal
- alias_set: custom
-
- name: GuardProto
gen_boilerplate: false
@@ -2720,16 +2681,6 @@
- name: LoadDynamicSlot
gen_boilerplate: false
-- name: LoadDynamicSlotFromOffset
- operands:
- slots: Slots
- offset: Int32
- result_type: Value
- movable: true
- congruent_to: if_operands_equal
- alias_set: custom
- generate_lir: true
-
# Inline call to access a function's environment (scope chain).
- name: FunctionEnvironment
operands:
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
@@ -5763,13 +5763,16 @@ void MacroAssembler::branchTestType(Condition cond, Register tag,
}
}
-void MacroAssembler::branchTestObjShapeListImpl(
- Register obj, Register shapeElements, size_t itemSize,
- Register shapeScratch, Register endScratch, Register spectreScratch,
- Label* fail) {
+void MacroAssembler::branchTestObjShapeList(
+ Condition cond, Register obj, Register shapeElements, Register shapeScratch,
+ Register endScratch, Register spectreScratch, Label* label) {
+ MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
bool needSpectreMitigations = spectreScratch != InvalidReg;
Label done;
+ Label* onMatch = cond == Assembler::Equal ? label : &done;
+ Label* onNoMatch = cond == Assembler::Equal ? &done : label;
// Load the object's shape pointer into shapeScratch, and prepare to compare
// it with the shapes in the list. The shapes are stored as private values so
@@ -5780,7 +5783,7 @@ void MacroAssembler::branchTestObjShapeListImpl(
Address lengthAddr(shapeElements,
ObjectElements::offsetOfInitializedLength());
load32(lengthAddr, endScratch);
- branch32(Assembler::Equal, endScratch, Imm32(0), fail);
+ branch32(Assembler::Equal, endScratch, Imm32(0), onNoMatch);
BaseObjectElementIndex endPtrAddr(shapeElements, endScratch);
computeEffectiveAddress(endPtrAddr, endScratch);
@@ -5794,38 +5797,21 @@ void MacroAssembler::branchTestObjShapeListImpl(
if (needSpectreMitigations) {
move32(Imm32(0), spectreScratch);
}
- branchPtr(Assembler::Equal, Address(shapeElements, 0), shapeScratch, &done);
+ branchPtr(Assembler::Equal, Address(shapeElements, 0), shapeScratch, onMatch);
if (needSpectreMitigations) {
spectreMovePtr(Assembler::Equal, spectreScratch, obj);
}
// Advance to next shape and loop if not finished.
- addPtr(Imm32(itemSize), shapeElements);
+ addPtr(Imm32(sizeof(Value)), shapeElements);
branchPtr(Assembler::Below, shapeElements, endScratch, &loop);
- jump(fail);
+ if (cond == Assembler::NotEqual) {
+ jump(label);
+ }
bind(&done);
}
-void MacroAssembler::branchTestObjShapeList(
- Register obj, Register shapeElements, Register shapeScratch,
- Register endScratch, Register spectreScratch, Label* fail) {
- branchTestObjShapeListImpl(obj, shapeElements, sizeof(Value), shapeScratch,
- endScratch, spectreScratch, fail);
-}
-
-void MacroAssembler::branchTestObjShapeListSetOffset(
- Register obj, Register shapeElements, Register offset,
- Register shapeScratch, Register endScratch, Register spectreScratch,
- Label* fail) {
- branchTestObjShapeListImpl(obj, shapeElements, 2 * sizeof(Value),
- shapeScratch, endScratch, spectreScratch, fail);
-
- // The shapeElements register points to the matched shape (if found).
- // The corresponding offset is saved in the array as the next value.
- load32(Address(shapeElements, sizeof(Value)), offset);
-}
-
void MacroAssembler::branchTestObjCompartment(Condition cond, Register obj,
const Address& compartment,
Register scratch, Label* label) {
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
@@ -1843,21 +1843,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
const Shape* shape,
Label* label);
- private:
- void branchTestObjShapeListImpl(Register obj, Register shapeElements,
- size_t itemSize, Register shapeScratch,
- Register endScratch, Register spectreScratch,
- Label* fail);
-
- public:
- void branchTestObjShapeList(Register obj, Register shapeElements,
- Register shapeScratch, Register endScratch,
- Register spectreScratch, Label* fail);
-
- void branchTestObjShapeListSetOffset(Register obj, Register shapeElements,
- Register offset, Register shapeScratch,
- Register endScratch,
- Register spectreScratch, Label* fail);
+ void branchTestObjShapeList(Condition cond, Register obj,
+ Register shapeElements, Register shapeScratch,
+ Register endScratch, Register spectreScratch,
+ Label* label);
inline void branchTestClassIsFunction(Condition cond, Register clasp,
Label* label);
diff --git a/js/src/jit/ShapeList.cpp b/js/src/jit/ShapeList.cpp
@@ -94,99 +94,3 @@ bool ShapeListObject::traceWeak(JSTracer* trc) {
return length != 0;
}
-
-const JSClass ShapeListWithOffsetsObject::class_ = {
- "JIT ShapeList",
- 0,
- &classOps_,
-};
-
-const JSClassOps ShapeListWithOffsetsObject::classOps_ = {
- nullptr, // addProperty
- nullptr, // delProperty
- nullptr, // enumerate
- nullptr, // newEnumerate
- nullptr, // resolve
- nullptr, // mayResolve
- nullptr, // finalize
- nullptr, // call
- nullptr, // construct
- ShapeListWithOffsetsObject::trace, // trace
-};
-
-/* static */ ShapeListWithOffsetsObject* ShapeListWithOffsetsObject::create(
- JSContext* cx) {
- NativeObject* obj = NewTenuredObjectWithGivenProto(cx, &class_, nullptr);
- if (!obj) {
- return nullptr;
- }
-
- // Register this object so the GC can sweep its weak pointers.
- if (!cx->zone()->registerObjectWithWeakPointers(obj)) {
- ReportOutOfMemory(cx);
- return nullptr;
- }
-
- return &obj->as<ShapeListWithOffsetsObject>();
-}
-
-Shape* ShapeListWithOffsetsObject::getShape(uint32_t index) const {
- Shape* shape = getShapeUnbarriered(index);
- gc::ReadBarrier(shape);
- return shape;
-}
-
-Shape* ShapeListWithOffsetsObject::getShapeUnbarriered(uint32_t index) const {
- Value value = ListObject::get(index * 2);
- return static_cast<Shape*>(value.toPrivate());
-}
-
-uint32_t ShapeListWithOffsetsObject::getOffset(uint32_t index) const {
- Value value = ListObject::get(index * 2 + 1);
- return value.toPrivateUint32();
-}
-
-uint32_t ShapeListWithOffsetsObject::numShapes() const {
- MOZ_ASSERT(length() % 2 == 0);
- return length() / 2;
-};
-
-void ShapeListWithOffsetsObject::trace(JSTracer* trc, JSObject* obj) {
- if (trc->traceWeakEdges()) {
- obj->as<ShapeListWithOffsetsObject>().traceWeak(trc);
- }
-}
-
-bool ShapeListWithOffsetsObject::traceWeak(JSTracer* trc) {
- uint32_t length = getDenseInitializedLength();
- if (length == 0) {
- return false; // Object may be uninitialized.
- }
-
- const HeapSlot* src = elements_;
- const HeapSlot* end = src + length;
- HeapSlot* dst = elements_;
- while (src != end) {
- Shape* shape = static_cast<Shape*>(src[0].toPrivate());
- uint32_t offset = src[1].toPrivateUint32();
- MOZ_ASSERT(shape->is<Shape>());
- if (TraceManuallyBarrieredWeakEdge(trc, &shape,
- "ShapeListWithOffsetsObject shape")) {
- dst[0].unbarrieredSet(PrivateValue(shape));
- dst[1].unbarrieredSet(PrivateUint32Value(offset));
- dst += 2;
- }
- src += 2;
- }
-
- MOZ_ASSERT(dst <= end);
- uint32_t newLength = dst - elements_;
- setDenseInitializedLength(newLength);
-
- if (length != newLength) {
- JitSpew(JitSpew_StubFolding, "Cleared %u/%u shapes from %p",
- (length - newLength) / 2, (length) / 2, this);
- }
-
- return length != 0;
-}
diff --git a/js/src/jit/ShapeList.h b/js/src/jit/ShapeList.h
@@ -35,28 +35,6 @@ class ShapeListObject : public ListObject {
bool traceWeak(JSTracer* trc);
};
-// Similar to ShapeListObject. But here we keep a list of the shape and the
-// corresponding offset of a particular access (e.g. obj.a).
-// The values are saved as: [shape1, offset1, shape2, offset2 ...].
-class ShapeListWithOffsetsObject : public ListObject {
- public:
- static const JSClass class_;
- static const JSClassOps classOps_;
-
- static constexpr size_t MaxLength = 16;
-
- static ShapeListWithOffsetsObject* create(JSContext* cx);
- static void trace(JSTracer* trc, JSObject* obj);
-
- uint32_t numShapes() const;
- Shape* getShape(uint32_t index) const;
- Shape* getShapeUnbarriered(uint32_t index) const;
-
- uint32_t getOffset(uint32_t index) const;
-
- bool traceWeak(JSTracer* trc);
-};
-
} // namespace js::jit
#endif // jit_ShapeList_h
diff --git a/js/src/jit/StubFolding.cpp b/js/src/jit/StubFolding.cpp
@@ -24,47 +24,43 @@
using namespace js;
using namespace js::jit;
-static bool TryFoldingGuardShapes(JSContext* cx, ICFallbackStub* fallback,
- JSScript* script, ICScript* icScript) {
- // Try folding similar stubs with GuardShapes
- // into GuardMultipleShapes or GuardMultipleShapesToOffset
-
+bool js::jit::TryFoldingStubs(JSContext* cx, ICFallbackStub* fallback,
+ JSScript* script, ICScript* icScript) {
ICEntry* icEntry = icScript->icEntryForStub(fallback);
ICStub* entryStub = icEntry->firstStub();
- ICCacheIRStub* firstStub = entryStub->toCacheIRStub();
- // The caller guarantees that there are at least two stubs.
- MOZ_ASSERT(entryStub != fallback);
- MOZ_ASSERT(!firstStub->next()->isFallback());
+ // Don't fold unless there are at least two stubs.
+ if (entryStub == fallback) {
+ return true;
+ }
+ ICCacheIRStub* firstStub = entryStub->toCacheIRStub();
+ if (firstStub->next()->isFallback()) {
+ return true;
+ }
const uint8_t* firstStubData = firstStub->stubDataStart();
const CacheIRStubInfo* stubInfo = firstStub->stubInfo();
// Check to see if:
// a) all of the stubs in this chain have the exact same code.
- // b) all of the stubs have the same stub field data, except for a single
- // GuardShape (and/or consecutive RawInt32) where they differ.
+ // b) all of the stubs have the same stub field data, except
+ // for a single GuardShape where they differ.
// c) at least one stub after the first has a non-zero entry count.
// d) All shapes in the GuardShape have the same realm.
//
// If all of these conditions hold, then we generate a single stub
- // that covers all the existing cases by
- // 1) replacing GuardShape with GuardMultipleShapes.
- // 2) replacing Load/Store with equivalent LoadToOffset/StoreToOffset
+ // that covers all the existing cases by replacing GuardShape with
+ // GuardMultipleShapes.
uint32_t numActive = 0;
- mozilla::Maybe<uint32_t> foldableShapeOffset;
- mozilla::Maybe<uint32_t> foldableOffsetOffset;
+ mozilla::Maybe<uint32_t> foldableFieldOffset;
GCVector<Value, 8> shapeList(cx);
- GCVector<Value, 8> offsetList(cx);
- // Helper function: Keep list of different shapes.
- // Can fail on OOM or for cross-realm shapes.
+ // Try to add a shape to the list. Can fail on OOM or for cross-realm shapes.
// Returns true if the shape was successfully added to the list, and false
// (with no pending exception) otherwise.
auto addShape = [&shapeList, cx](uintptr_t rawShape) -> bool {
Shape* shape = reinterpret_cast<Shape*>(rawShape);
-
// Only add same realm shapes.
if (shape->realm() != cx->realm()) {
return false;
@@ -79,175 +75,75 @@ static bool TryFoldingGuardShapes(JSContext* cx, ICFallbackStub* fallback,
return true;
};
- // Helper function: Keep list of "possible" different offsets (slotOffset).
- // At this stage we don't know if they differ. Therefore only keep track
- // of the first offset until we see a different offset and fill list equal to
- // shapeList if that happens.
- auto lazyAddOffset = [&offsetList, &shapeList, cx](uintptr_t slotOffset) {
- Value v = PrivateUint32Value(static_cast<uint32_t>(slotOffset));
- if (offsetList.length() == 1) {
- if (v == offsetList[0]) return true;
-
- while (offsetList.length() + 1 < shapeList.length()) {
- if (!offsetList.append(offsetList[0])) {
- cx->recoverFromOutOfMemory();
- return false;
- }
- }
- }
-
- if (!offsetList.append(v)) {
- cx->recoverFromOutOfMemory();
- return false;
- }
- return true;
- };
-
-#ifdef JS_JITSPEW
- JitSpew(JitSpew_StubFolding, "Trying to fold stubs at offset %u @ %s:%u:%u",
- fallback->pcOffset(), script->filename(), script->lineno(),
- script->column().oneOriginValue());
-
- if (JitSpewEnabled(JitSpew_StubFoldingDetails)) {
- Fprinter& printer(JitSpewPrinter());
- uint32_t i = 0;
- for (ICCacheIRStub* stub = firstStub; stub; stub = stub->nextCacheIR()) {
- printer.printf("- stub %d (enteredCount: %d)\n", i, stub->enteredCount());
- ICCacheIRStub* cache_stub = stub->toCacheIRStub();
-
- CacheIRReader reader(cache_stub->stubInfo());
- SpewCacheIROps(printer, " ", cache_stub->stubInfo());
- i++;
- }
- }
-#endif
-
- // Find the offset of the first Shape that differs.
- // Also see if the next field is RawInt32, which is
- // the case for a Fixed/Dynamic slot if it follows the ShapeGuard.
for (ICCacheIRStub* other = firstStub->nextCacheIR(); other;
other = other->nextCacheIR()) {
// Verify that the stubs share the same code.
if (other->stubInfo() != stubInfo) {
return true;
}
+ const uint8_t* otherStubData = other->stubDataStart();
if (other->enteredCount() > 0) {
numActive++;
}
- if (foldableShapeOffset.isSome()) {
- // Already found.
- // Continue through all stubs to run above code.
- continue;
- }
-
- const uint8_t* otherStubData = other->stubDataStart();
uint32_t fieldIndex = 0;
size_t offset = 0;
while (stubInfo->fieldType(fieldIndex) != StubField::Type::Limit) {
StubField::Type fieldType = stubInfo->fieldType(fieldIndex);
- // Continue if the fields have same value.
- if (StubField::sizeIsInt64(fieldType)) {
- if (stubInfo->getStubRawInt64(firstStubData, offset) ==
- stubInfo->getStubRawInt64(otherStubData, offset)) {
- offset += StubField::sizeInBytes(fieldType);
- fieldIndex++;
- continue;
+ if (StubField::sizeIsWord(fieldType)) {
+ uintptr_t firstRaw = stubInfo->getStubRawWord(firstStubData, offset);
+ uintptr_t otherRaw = stubInfo->getStubRawWord(otherStubData, offset);
+
+ if (firstRaw != otherRaw) {
+ if (fieldType != StubField::Type::WeakShape) {
+ // Case 1: a field differs that is not a Shape. We only support
+ // folding GuardShape to GuardMultipleShapes.
+ return true;
+ }
+ if (foldableFieldOffset.isNothing()) {
+ // Case 2: this is the first field where the stub data differs.
+ foldableFieldOffset.emplace(offset);
+ if (!addShape(firstRaw) || !addShape(otherRaw)) {
+ return true;
+ }
+ } else if (*foldableFieldOffset == offset) {
+ // Case 3: this is the corresponding offset in a different stub.
+ if (!addShape(otherRaw)) {
+ return true;
+ }
+ } else {
+ // Case 4: we have found more than one field that differs.
+ return true;
+ }
}
} else {
- MOZ_ASSERT(StubField::sizeIsWord(fieldType));
- if (stubInfo->getStubRawWord(firstStubData, offset) ==
- stubInfo->getStubRawWord(otherStubData, offset)) {
- offset += StubField::sizeInBytes(fieldType);
- fieldIndex++;
- continue;
- }
- }
+ MOZ_ASSERT(StubField::sizeIsInt64(fieldType));
- // Early abort if it is a non-shape field that differs.
- if (fieldType != StubField::Type::WeakShape) {
- return true;
+ // We do not support folding any ops with int64-sized fields.
+ if (stubInfo->getStubRawInt64(firstStubData, offset) !=
+ stubInfo->getStubRawInt64(otherStubData, offset)) {
+ return true;
+ }
}
- // Save the offset
- foldableShapeOffset.emplace(offset);
-
- // Test if the consecutive field is potentially Load{Fixed|Dynamic}Slot
offset += StubField::sizeInBytes(fieldType);
fieldIndex++;
- if (stubInfo->fieldType(fieldIndex) == StubField::Type::RawInt32) {
- foldableOffsetOffset.emplace(offset);
- }
-
- break;
}
- }
- if (foldableShapeOffset.isNothing()) {
- return true;
+ // We should never attach two completely identical stubs.
+ MOZ_ASSERT(foldableFieldOffset.isSome());
}
if (numActive == 0) {
return true;
}
- // Make sure the shape and offset is the only value that differ.
- // Collect the shape and offset values at the same time.
- for (ICCacheIRStub* stub = firstStub; stub; stub = stub->nextCacheIR()) {
- const uint8_t* stubData = stub->stubDataStart();
- uint32_t fieldIndex = 0;
- size_t offset = 0;
-
- while (stubInfo->fieldType(fieldIndex) != StubField::Type::Limit) {
- StubField::Type fieldType = stubInfo->fieldType(fieldIndex);
- if (offset == *foldableShapeOffset) {
- // Save the shapes of all stubs.
- MOZ_ASSERT(fieldType == StubField::Type::WeakShape);
- uintptr_t raw = stubInfo->getStubRawWord(stubData, offset);
- if (!addShape(raw)) {
- return true;
- }
- } else if (foldableOffsetOffset.isSome() &&
- offset == *foldableOffsetOffset) {
- // Save the offsets of all stubs.
- MOZ_ASSERT(fieldType == StubField::Type::RawInt32);
- uintptr_t raw = stubInfo->getStubRawWord(stubData, offset);
- if (!lazyAddOffset(raw)) {
- return true;
- }
- } else {
- // Check all other fields are the same.
- if (StubField::sizeIsInt64(fieldType)) {
- if (stubInfo->getStubRawInt64(firstStubData, offset) !=
- stubInfo->getStubRawInt64(stubData, offset)) {
- return true;
- }
- } else {
- MOZ_ASSERT(StubField::sizeIsWord(fieldType));
- if (stubInfo->getStubRawWord(firstStubData, offset) !=
- stubInfo->getStubRawWord(stubData, offset)) {
- return true;
- }
- }
- }
-
- offset += StubField::sizeInBytes(fieldType);
- fieldIndex++;
- }
- }
-
- // Clone the CacheIR and replace
- // - specific GuardShape with GuardMultipleShapes.
- // or
- // (multiple distinct values in offsetList)
- // - specific GuardShape with GuardMultipleShapesToOffset.
- // - subsequent Load / Store with LoadToOffset / StoreToOffset
+ // Clone the CacheIR, replacing GuardShape with GuardMultipleShapes.
CacheIRWriter writer(cx);
CacheIRReader reader(stubInfo);
CacheIRCloner cloner(firstStub);
- bool hasSlotOffsets = offsetList.length() > 1;
// Initialize the operands.
CacheKind cacheKind = stubInfo->kind();
@@ -255,120 +151,40 @@ static bool TryFoldingGuardShapes(JSContext* cx, ICFallbackStub* fallback,
writer.setInputOperandId(i);
}
- // Create the shapeList to bake in the new stub.
- Rooted<ListObject*> shapeObj(cx);
- {
- gc::AutoSuppressGC suppressGC(cx);
-
- if (!hasSlotOffsets) {
- shapeObj.set(ShapeListObject::create(cx));
- } else {
- shapeObj.set(ShapeListWithOffsetsObject::create(cx));
- }
-
- if (!shapeObj) {
- return false;
- }
-
- MOZ_ASSERT_IF(hasSlotOffsets, shapeList.length() == offsetList.length());
-
- for (uint32_t i = 0; i < shapeList.length(); i++) {
- if (!shapeObj->append(cx, shapeList[i])) {
- cx->recoverFromOutOfMemory();
- return false;
- }
-
- if (hasSlotOffsets) {
- if (!shapeObj->append(cx, offsetList[i])) {
- cx->recoverFromOutOfMemory();
- return false;
- }
- }
-
- MOZ_ASSERT(static_cast<Shape*>(shapeList[i].toPrivate())->realm() ==
- shapeObj->realm());
- }
- }
-
- mozilla::Maybe<Int32OperandId> offsetId;
- bool shapeSuccess = false;
- bool offsetSuccess = false;
+ bool success = false;
while (reader.more()) {
CacheOp op = reader.readOp();
switch (op) {
case CacheOp::GuardShape: {
auto [objId, shapeOffset] = reader.argsForGuardShape();
- if (shapeOffset != *foldableShapeOffset) {
- // Unrelated GuardShape.
+ if (shapeOffset == *foldableFieldOffset) {
+ // Ensure that the allocation of the ShapeListObject doesn't trigger a
+ // GC and free the stubInfo we're currently reading. Note that
+ // AutoKeepJitScripts isn't sufficient, because optimized stubs can be
+ // discarded even if the JitScript is preserved.
+ gc::AutoSuppressGC suppressGC(cx);
+
+ Rooted<ShapeListObject*> shapeObj(cx, ShapeListObject::create(cx));
+ if (!shapeObj) {
+ return false;
+ }
+ for (uint32_t i = 0; i < shapeList.length(); i++) {
+ if (!shapeObj->append(cx, shapeList[i])) {
+ return false;
+ }
+
+ MOZ_ASSERT(static_cast<Shape*>(shapeList[i].toPrivate())->realm() ==
+ shapeObj->realm());
+ }
+
+ writer.guardMultipleShapes(objId, shapeObj);
+ success = true;
+ } else {
WeakHeapPtr<Shape*>& ptr =
stubInfo->getStubField<StubField::Type::WeakShape>(firstStub,
shapeOffset);
writer.guardShape(objId, ptr.unbarrieredGet());
- break;
- }
-
- if (hasSlotOffsets) {
- offsetId.emplace(writer.guardMultipleShapesToOffset(objId, shapeObj));
- } else {
- writer.guardMultipleShapes(objId, shapeObj);
- }
- shapeSuccess = true;
- break;
- }
- case CacheOp::LoadFixedSlotResult: {
- auto [objId, offsetOffset] = reader.argsForLoadFixedSlotResult();
- if (!hasSlotOffsets || offsetOffset != *foldableOffsetOffset) {
- // Unrelated LoadFixedSlotResult
- uint32_t offset = stubInfo->getStubRawWord(firstStub, offsetOffset);
- writer.loadFixedSlotResult(objId, offset);
- break;
- }
-
- MOZ_ASSERT(offsetId.isSome());
- writer.loadFixedSlotFromOffsetResult(objId, offsetId.value());
- offsetSuccess = true;
- break;
- }
- case CacheOp::StoreFixedSlot: {
- auto [objId, offsetOffset, rhsId] = reader.argsForStoreFixedSlot();
- if (!hasSlotOffsets || offsetOffset != *foldableOffsetOffset) {
- // Unrelated StoreFixedSlot
- uint32_t offset = stubInfo->getStubRawWord(firstStub, offsetOffset);
- writer.storeFixedSlot(objId, offset, rhsId);
- break;
- }
-
- MOZ_ASSERT(offsetId.isSome());
- writer.storeFixedSlotFromOffset(objId, offsetId.value(), rhsId);
- offsetSuccess = true;
- break;
- }
- case CacheOp::StoreDynamicSlot: {
- auto [objId, offsetOffset, rhsId] = reader.argsForStoreDynamicSlot();
- if (!hasSlotOffsets || offsetOffset != *foldableOffsetOffset) {
- // Unrelated StoreDynamicSlot
- uint32_t offset = stubInfo->getStubRawWord(firstStub, offsetOffset);
- writer.storeDynamicSlot(objId, offset, rhsId);
- break;
}
-
- MOZ_ASSERT(offsetId.isSome());
- writer.storeDynamicSlotFromOffset(objId, offsetId.value(), rhsId);
- offsetSuccess = true;
- break;
- }
- case CacheOp::LoadDynamicSlotResult: {
- auto [objId, offsetOffset] = reader.argsForLoadDynamicSlotResult();
- if (!hasSlotOffsets || offsetOffset != *foldableOffsetOffset) {
- // Unrelated LoadDynamicSlotResult
- uint32_t offset = stubInfo->getStubRawWord(firstStub, offsetOffset);
- writer.loadDynamicSlotResult(objId, offset);
- break;
- }
-
- MOZ_ASSERT(offsetId.isSome());
- writer.loadDynamicSlotFromOffsetResult(objId, offsetId.value());
- offsetSuccess = true;
break;
}
default:
@@ -376,30 +192,9 @@ static bool TryFoldingGuardShapes(JSContext* cx, ICFallbackStub* fallback,
break;
}
}
-
- if (!shapeSuccess) {
+ if (!success) {
// If the shape field that differed was not part of a GuardShape,
// we can't fold these stubs together.
- JitSpew(JitSpew_StubFolding,
- "Foldable shape field at offset %u was not a GuardShape "
- "(icScript: %p) with %zu shapes (%s:%u:%u)",
- fallback->pcOffset(), icScript, shapeList.length(),
- script->filename(), script->lineno(),
- script->column().oneOriginValue());
- return true;
- }
-
- if (hasSlotOffsets && !offsetSuccess) {
- // If we found a differing offset field but it was not part of the
- // Load{Fixed | Dynamic}SlotResult then we can't fold these stubs
- // together.
- JitSpew(JitSpew_StubFolding,
- "Failed to fold GuardShape into GuardMultipleShapesToOffset at "
- "offset %u "
- "(icScript: %p) with %zu shapes (%s:%u:%u)",
- fallback->pcOffset(), icScript, shapeList.length(),
- script->filename(), script->lineno(),
- script->column().oneOriginValue());
return true;
}
@@ -420,40 +215,7 @@ static bool TryFoldingGuardShapes(JSContext* cx, ICFallbackStub* fallback,
script->filename(), script->lineno(),
script->column().oneOriginValue());
-#ifdef JS_JITSPEW
- if (JitSpewEnabled(JitSpew_StubFoldingDetails)) {
- ICStub* newEntryStub = icEntry->firstStub();
- ICCacheIRStub* newStub = newEntryStub->toCacheIRStub();
-
- Fprinter& printer(JitSpewPrinter());
- printer.printf("- stub 0 (enteredCount: %d)\n", newStub->enteredCount());
- CacheIRReader reader(newStub->stubInfo());
- SpewCacheIROps(printer, " ", newStub->stubInfo());
- }
-#endif
-
fallback->setMayHaveFoldedStub();
-
- return true;
-}
-
-bool js::jit::TryFoldingStubs(JSContext* cx, ICFallbackStub* fallback,
- JSScript* script, ICScript* icScript) {
- ICEntry* icEntry = icScript->icEntryForStub(fallback);
- ICStub* entryStub = icEntry->firstStub();
-
- // Don't fold unless there are at least two stubs.
- if (entryStub == fallback) {
- return true;
- }
-
- ICCacheIRStub* firstStub = entryStub->toCacheIRStub();
- if (firstStub->next()->isFallback()) {
- return true;
- }
-
- if (!TryFoldingGuardShapes(cx, fallback, script, icScript)) return false;
-
return true;
}
@@ -475,10 +237,8 @@ bool js::jit::AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer,
const uint8_t* stubData = stub->stubDataStart();
mozilla::Maybe<uint32_t> shapeFieldOffset;
- mozilla::Maybe<uint32_t> offsetFieldOffset;
RootedValue newShape(cx);
- RootedValue newOffset(cx);
- Rooted<ListObject*> shapeList(cx);
+ Rooted<ShapeListObject*> foldedShapes(cx);
CacheIRReader stubReader(stubInfo);
CacheIRReader newReader(writer);
@@ -491,72 +251,19 @@ bool js::jit::AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer,
if (newOp != CacheOp::GuardShape) {
return false;
}
- // Check that the object being guarded is the same.
- if (newReader.objOperandId() != stubReader.objOperandId()) {
- return false;
- }
-
- // Check that the shape offset is the same.
- uint32_t newShapeOffset = newReader.stubOffset();
- uint32_t stubShapesOffset = stubReader.stubOffset();
- if (newShapeOffset != stubShapesOffset) {
- return false;
- }
-
- MOZ_ASSERT(shapeList == nullptr);
- shapeFieldOffset.emplace(newShapeOffset);
-
- // Get the shape from the new stub
- StubField shapeField =
- writer.readStubField(newShapeOffset, StubField::Type::WeakShape);
- Shape* shape = reinterpret_cast<Shape*>(shapeField.asWord());
- newShape = PrivateValue(shape);
-
- // Get the shape array from the old stub.
- JSObject* obj = stubInfo->getStubField<StubField::Type::JSObject>(
- stub, stubShapesOffset);
- shapeList = &obj->as<ShapeListObject>();
- MOZ_ASSERT(shapeList->compartment() == shape->compartment());
-
- // Don't add a shape if it's from a different realm than the first
- // shape.
- //
- // Since the list was created in the realm which guarded all the shapes
- // added to it, we can use its realm to check and ensure we're not
- // adding a cross-realm shape.
- //
- // The assert verifies this property by checking the first element has
- // the same realm (and since everything in the list has the same realm,
- // checking the first element suffices)
- Realm* shapesRealm = shapeList->realm();
- MOZ_ASSERT_IF(
- !shapeList->isEmpty(),
- shapeList->as<ShapeListObject>().getUnbarriered(0)->realm() ==
- shapesRealm);
- if (shapesRealm != shape->realm()) {
- return false;
- }
- break;
- }
- case CacheOp::GuardMultipleShapesToOffset: {
- // Check that the new stub has a corresponding GuardShape.
- if (newOp != CacheOp::GuardShape) {
- return false;
- }
// Check that the object being guarded is the same.
if (newReader.objOperandId() != stubReader.objOperandId()) {
return false;
}
- // Check that the shape offset is the same.
+ // Check that the field offset is the same.
uint32_t newShapeOffset = newReader.stubOffset();
uint32_t stubShapesOffset = stubReader.stubOffset();
if (newShapeOffset != stubShapesOffset) {
return false;
}
-
- MOZ_ASSERT(shapeList == nullptr);
+ MOZ_ASSERT(shapeFieldOffset.isNothing());
shapeFieldOffset.emplace(newShapeOffset);
// Get the shape from the new stub
@@ -566,10 +273,10 @@ bool js::jit::AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer,
newShape = PrivateValue(shape);
// Get the shape array from the old stub.
- JSObject* obj = stubInfo->getStubField<StubField::Type::JSObject>(
+ JSObject* shapeList = stubInfo->getStubField<StubField::Type::JSObject>(
stub, stubShapesOffset);
- shapeList = &obj->as<ShapeListWithOffsetsObject>();
- MOZ_ASSERT(shapeList->compartment() == shape->compartment());
+ foldedShapes = &shapeList->as<ShapeListObject>();
+ MOZ_ASSERT(foldedShapes->compartment() == shape->compartment());
// Don't add a shape if it's from a different realm than the first
// shape.
@@ -581,84 +288,13 @@ bool js::jit::AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer,
// The assert verifies this property by checking the first element has
// the same realm (and since everything in the list has the same realm,
// checking the first element suffices)
- Realm* shapesRealm = shapeList->realm();
- MOZ_ASSERT_IF(
- !shapeList->isEmpty(),
- shapeList->as<ShapeListWithOffsetsObject>().getShape(0)->realm() ==
- shapesRealm);
+ Realm* shapesRealm = foldedShapes->realm();
+ MOZ_ASSERT_IF(!foldedShapes->isEmpty(),
+ foldedShapes->getUnbarriered(0)->realm() == shapesRealm);
if (shapesRealm != shape->realm()) {
return false;
}
- // Consume the offsetId argument.
- stubReader.skip();
- break;
- }
- case CacheOp::LoadFixedSlotFromOffsetResult:
- case CacheOp::LoadDynamicSlotFromOffsetResult: {
- // Check that the new stub has a corresponding
- // Load{Fixed|Dynamic}SlotResult
- if (stubOp == CacheOp::LoadFixedSlotFromOffsetResult &&
- newOp != CacheOp::LoadFixedSlotResult) {
- return false;
- }
- if (stubOp == CacheOp::LoadDynamicSlotFromOffsetResult &&
- newOp != CacheOp::LoadDynamicSlotResult) {
- return false;
- }
-
- // Verify operand ID.
- if (newReader.objOperandId() != stubReader.objOperandId()) {
- return false;
- }
-
- MOZ_ASSERT(offsetFieldOffset.isNothing());
- offsetFieldOffset.emplace(newReader.stubOffset());
-
- // Get the offset from the new stub
- StubField offsetField =
- writer.readStubField(*offsetFieldOffset, StubField::Type::RawInt32);
- newOffset = PrivateUint32Value(offsetField.asWord());
-
- // Consume the offsetId argument.
- stubReader.skip();
- break;
- }
- case CacheOp::StoreFixedSlotFromOffset:
- case CacheOp::StoreDynamicSlotFromOffset: {
- // Check that the new stub has a corresponding Store{Fixed|Dynamic}Slot
- if (stubOp == CacheOp::StoreFixedSlotFromOffset &&
- newOp != CacheOp::StoreFixedSlot) {
- return false;
- }
- if (stubOp == CacheOp::StoreDynamicSlotFromOffset &&
- newOp != CacheOp::StoreDynamicSlot) {
- return false;
- }
-
- // Verify operand ID.
- if (newReader.objOperandId() != stubReader.objOperandId()) {
- return false;
- }
-
- MOZ_ASSERT(offsetFieldOffset.isNothing());
- offsetFieldOffset.emplace(newReader.stubOffset());
-
- // Get the offset from the new stub
- StubField offsetField =
- writer.readStubField(*offsetFieldOffset, StubField::Type::RawInt32);
- newOffset = PrivateUint32Value(offsetField.asWord());
-
- // Consume the offsetId argument.
- stubReader.skip();
-
- // Verify rhs ID.
- if (newReader.valOperandId() != stubReader.valOperandId()) {
- return false;
- }
-
- MOZ_ASSERT(stubReader.peekOp() == CacheOp::ReturnFromIC);
- MOZ_ASSERT(newReader.peekOp() == CacheOp::ReturnFromIC);
break;
}
default: {
@@ -684,40 +320,27 @@ bool js::jit::AddToFoldedStub(JSContext* cx, const CacheIRWriter& writer,
return false;
}
- if (!writer.stubDataEqualsIgnoringShapeAndOffset(stubData, *shapeFieldOffset,
- offsetFieldOffset)) {
+ // Check to verify that all the other stub fields are the same.
+ if (!writer.stubDataEqualsIgnoring(stubData, *shapeFieldOffset)) {
return false;
}
- // ShapeListWithSlotsObject uses two spaces per shape.
- uint32_t numShapes = offsetFieldOffset.isNothing() ? shapeList->length()
- : shapeList->length() / 2;
-
// Limit the maximum number of shapes we will add before giving up.
// If we give up, transition the stub.
- if (numShapes == ShapeListObject::MaxLength) {
+ if (foldedShapes->length() == ShapeListObject::MaxLength) {
MOZ_ASSERT(fallback->state().mode() != ICState::Mode::Generic);
fallback->state().forceTransition();
fallback->discardStubs(cx->zone(), icEntry);
return false;
}
- if (!shapeList->append(cx, newShape)) {
+ if (!foldedShapes->append(cx, newShape)) {
cx->recoverFromOutOfMemory();
return false;
}
- if (offsetFieldOffset.isSome()) {
- if (!shapeList->append(cx, newOffset)) {
- // Drop corresponding shape if we failed adding offset.
- shapeList->shrinkElements(cx, shapeList->length() - 1);
- cx->recoverFromOutOfMemory();
- return false;
- }
- }
+ JitSpew(JitSpew_StubFolding, "ShapeListObject %p: new length: %u",
+ foldedShapes.get(), foldedShapes->length());
- JitSpew(JitSpew_StubFolding, "ShapeList%sObject %p: new length: %u",
- offsetFieldOffset.isNothing() ? "" : "WithOffset", shapeList.get(),
- shapeList->length());
return true;
}
diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp
@@ -1121,8 +1121,6 @@ bool ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
_(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, \
NoFloatPolicyAfter<2>>) \
_(MixPolicy<IntPtrPolicy<0>, IntPtrPolicy<1>, IntPtrPolicy<2>>) \
- _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, NoFloatPolicy<2>>) \
- _(MixPolicy<UnboxedInt32Policy<1>, NoFloatPolicy<2>>) \
_(NoFloatPolicy<0>) \
_(NoFloatPolicy<1>) \
_(NoFloatPolicy<2>) \
diff --git a/js/src/jit/WarpBuilder.cpp b/js/src/jit/WarpBuilder.cpp
@@ -3383,9 +3383,6 @@ bool WarpBuilder::buildIC(BytecodeLocation loc, CacheKind kind,
const WarpCacheIRBase* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc);
if (!cacheIRSnapshot) {
cacheIRSnapshot = getOpSnapshot<WarpCacheIRWithShapeList>(loc);
- if (!cacheIRSnapshot) {
- cacheIRSnapshot = getOpSnapshot<WarpCacheIRWithShapeListAndOffsets>(loc);
- }
}
if (cacheIRSnapshot) {
return TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, inputs);
diff --git a/js/src/jit/WarpCacheIRTranspiler.cpp b/js/src/jit/WarpCacheIRTranspiler.cpp
@@ -529,28 +529,6 @@ bool WarpCacheIRTranspiler::emitGuardMultipleShapes(ObjOperandId objId,
return true;
}
-bool WarpCacheIRTranspiler::emitGuardMultipleShapesToOffset(
- ObjOperandId objId, uint32_t shapesOffset, Int32OperandId offsetId) {
- MDefinition* obj = getOperand(objId);
-
- // Use MGuardShapeListToOffset if we snapshotted the list of shapes on the
- // main thread.
- MInstruction* ins;
- if (cacheIRSnapshot_->is<WarpCacheIRWithShapeListAndOffsets>()) {
- auto* shapes = (ShapeListWithOffsetsSnapshot*)cacheIRSnapshot_
- ->as<WarpCacheIRWithShapeListAndOffsets>()
- ->shapes();
- ins = MGuardShapeListToOffset::New(alloc(), obj, shapes);
- } else {
- MInstruction* shapeList = objectStubField(shapesOffset);
- ins = MGuardMultipleShapesToOffset::New(alloc(), obj, shapeList);
- ins->setBailoutKind(BailoutKind::StubFoldingGuardMultipleShapes);
- }
- add(ins);
-
- return defineOperand(offsetId, ins);
-}
-
bool WarpCacheIRTranspiler::emitGuardNullProto(ObjOperandId objId) {
MDefinition* def = getOperand(objId);
@@ -1043,21 +1021,6 @@ bool WarpCacheIRTranspiler::emitLoadDynamicSlot(ValOperandId resultId,
return defineOperand(resultId, load);
}
-bool WarpCacheIRTranspiler::emitLoadDynamicSlotFromOffsetResult(
- ObjOperandId objId, Int32OperandId offsetId) {
- MDefinition* obj = getOperand(objId);
- MDefinition* offset = getOperand(offsetId);
-
- auto* slots = MSlots::New(alloc(), obj);
- add(slots);
-
- auto* load = MLoadDynamicSlotFromOffset::New(alloc(), slots, offset);
- add(load);
-
- pushResult(load);
- return true;
-}
-
bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsNotObject(
ObjOperandId objId, uint32_t slotOffset) {
size_t slotIndex = int32StubField(slotOffset);
@@ -1949,52 +1912,6 @@ bool WarpCacheIRTranspiler::emitLoadFixedSlot(ValOperandId resultId,
return defineOperand(resultId, load);
}
-bool WarpCacheIRTranspiler::emitLoadFixedSlotFromOffsetResult(
- ObjOperandId objId, Int32OperandId offsetId) {
- MDefinition* obj = getOperand(objId);
- MDefinition* offset = getOperand(offsetId);
-
- auto* ins = MLoadFixedSlotFromOffset::New(alloc(), obj, offset);
- add(ins);
-
- pushResult(ins);
- return true;
-}
-
-bool WarpCacheIRTranspiler::emitStoreFixedSlotFromOffset(
- ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) {
- MDefinition* obj = getOperand(objId);
- MDefinition* offset = getOperand(offsetId);
- MDefinition* rhs = getOperand(rhsId);
-
- auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
- add(barrier);
-
- auto* store =
- MStoreFixedSlotFromOffset::NewBarriered(alloc(), obj, offset, rhs);
- addEffectful(store);
-
- return resumeAfter(store);
-}
-
-bool WarpCacheIRTranspiler::emitStoreDynamicSlotFromOffset(
- ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) {
- MDefinition* obj = getOperand(objId);
- MDefinition* offset = getOperand(offsetId);
- MDefinition* rhs = getOperand(rhsId);
-
- auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
- add(barrier);
-
- auto* slots = MSlots::New(alloc(), obj);
- add(slots);
-
- auto* store = MStoreDynamicSlotFromOffset::New(alloc(), slots, offset, rhs);
- addEffectful(store);
-
- return resumeAfter(store);
-}
-
bool WarpCacheIRTranspiler::emitLoadFixedSlotResult(ObjOperandId objId,
uint32_t offsetOffset) {
int32_t offset = int32StubField(offsetOffset);
diff --git a/js/src/jit/WarpOracle.cpp b/js/src/jit/WarpOracle.cpp
@@ -1106,7 +1106,6 @@ AbortReasonOr<Ok> WarpScriptOracle::maybeInlineIC(WarpOpSnapshotList& snapshots,
// List of shapes for a GuardMultipleShapes op with a small number of shapes.
mozilla::Maybe<ShapeListSnapshot> shapeList;
- mozilla::Maybe<ShapeListWithOffsetsSnapshot> shapeListWithOffsets;
// Only create a snapshot if all opcodes are supported by the transpiler.
CacheIRReader reader(stubInfo);
@@ -1224,22 +1223,6 @@ AbortReasonOr<Ok> WarpScriptOracle::maybeInlineIC(WarpOpSnapshotList& snapshots,
}
break;
}
- case CacheOp::GuardMultipleShapesToOffset: {
- auto args = reader.argsForGuardMultipleShapesToOffset();
- JSObject* shapes = stubInfo->getStubField<StubField::Type::JSObject>(
- stub, args.shapesOffset);
- auto* shapesObject = &shapes->as<ShapeListWithOffsetsObject>();
- MOZ_ASSERT(shapeListWithOffsets.isNothing());
- size_t numShapes = shapesObject->numShapes();
- if (ShapeListSnapshot::shouldSnapshot(numShapes)) {
- shapeListWithOffsets.emplace();
- for (size_t i = 0; i < numShapes; i++) {
- shapeListWithOffsets->init(i, shapesObject->getShape(i),
- shapesObject->getOffset(i));
- }
- }
- break;
- }
default:
reader.skip(opInfo.argLength);
break;
@@ -1293,18 +1276,11 @@ AbortReasonOr<Ok> WarpScriptOracle::maybeInlineIC(WarpOpSnapshotList& snapshots,
}
if (shapeList.isSome()) {
- MOZ_ASSERT(shapeListWithOffsets.isNothing());
if (!AddOpSnapshot<WarpCacheIRWithShapeList>(alloc_, snapshots, offset,
jitCode, stubInfo,
stubDataCopy, *shapeList)) {
return abort(AbortReason::Alloc);
}
- } else if (shapeListWithOffsets.isSome()) {
- if (!AddOpSnapshot<WarpCacheIRWithShapeListAndOffsets>(
- alloc_, snapshots, offset, jitCode, stubInfo, stubDataCopy,
- *shapeListWithOffsets)) {
- return abort(AbortReason::Alloc);
- }
} else {
if (!AddOpSnapshot<WarpCacheIR>(alloc_, snapshots, offset, jitCode,
stubInfo, stubDataCopy)) {
diff --git a/js/src/jit/WarpSnapshot.cpp b/js/src/jit/WarpSnapshot.cpp
@@ -216,20 +216,6 @@ void WarpCacheIRWithShapeList::dumpData(GenericPrinter& out) const {
}
}
-void WarpCacheIRWithShapeListAndOffsets::dumpData(GenericPrinter& out) const {
- WarpCacheIRBase::dumpData(out);
- uint32_t index = 0;
- for (Shape* shape : shapes_.shapes()) {
- out.printf(" shape %u: 0x%p\n", index, shape);
- index++;
- }
- index = 0;
- for (uint32_t offset : shapes_.offsets()) {
- out.printf(" offset %u: %u\n", index, offset);
- index++;
- }
-}
-
void WarpInlinedCall::dumpData(GenericPrinter& out) const {
out.printf(" scriptSnapshot: 0x%p\n", scriptSnapshot_);
out.printf(" info: 0x%p\n", info_);
@@ -467,11 +453,6 @@ void WarpCacheIRWithShapeList::traceData(JSTracer* trc) {
shapes_.trace(trc);
}
-void WarpCacheIRWithShapeListAndOffsets::traceData(JSTracer* trc) {
- WarpCacheIRBase::traceData(trc);
- shapes_.trace(trc);
-}
-
void WarpInlinedCall::traceData(JSTracer* trc) {
// Note: scriptSnapshot_ is traced through WarpSnapshot.
cacheIRSnapshot_->trace(trc);
diff --git a/js/src/jit/WarpSnapshot.h b/js/src/jit/WarpSnapshot.h
@@ -34,22 +34,21 @@ class CacheIRStubInfo;
class CompileInfo;
class WarpScriptSnapshot;
-#define WARP_OP_SNAPSHOT_LIST(_) \
- _(WarpArguments) \
- _(WarpRegExp) \
- _(WarpBuiltinObject) \
- _(WarpGetIntrinsic) \
- _(WarpGetImport) \
- _(WarpRest) \
- _(WarpBindUnqualifiedGName) \
- _(WarpVarEnvironment) \
- _(WarpLexicalEnvironment) \
- _(WarpClassBodyEnvironment) \
- _(WarpBailout) \
- _(WarpCacheIR) \
- _(WarpCacheIRWithShapeList) \
- _(WarpCacheIRWithShapeListAndOffsets) \
- _(WarpInlinedCall) \
+#define WARP_OP_SNAPSHOT_LIST(_) \
+ _(WarpArguments) \
+ _(WarpRegExp) \
+ _(WarpBuiltinObject) \
+ _(WarpGetIntrinsic) \
+ _(WarpGetImport) \
+ _(WarpRest) \
+ _(WarpBindUnqualifiedGName) \
+ _(WarpVarEnvironment) \
+ _(WarpLexicalEnvironment) \
+ _(WarpClassBodyEnvironment) \
+ _(WarpBailout) \
+ _(WarpCacheIR) \
+ _(WarpCacheIRWithShapeList) \
+ _(WarpInlinedCall) \
_(WarpPolymorphicTypes)
// WarpOpSnapshot is the base class for data attached to a single bytecode op by
@@ -283,27 +282,11 @@ class ShapeListSnapshot {
void trace(JSTracer* trc) const;
- protected:
+ private:
static constexpr size_t NumShapes = 4;
mozilla::Array<OffthreadGCPtr<Shape*>, NumShapes> shapes_{};
};
-class ShapeListWithOffsetsSnapshot : public ShapeListSnapshot {
- public:
- ShapeListWithOffsetsSnapshot() = default;
-
- void init(size_t index, Shape* shape, uint32_t offset) {
- MOZ_ASSERT(shape);
- shapes_[index].init(shape);
- offsets_[index] = offset;
- }
-
- const auto& offsets() const { return offsets_; }
-
- private:
- mozilla::Array<uint32_t, NumShapes> offsets_{};
-};
-
// Like WarpCacheIR, but also includes a ShapeListSnapshot for the
// GuardMultipleShapes CacheIR op.
class WarpCacheIRWithShapeList : public WarpCacheIRBase {
@@ -328,30 +311,6 @@ class WarpCacheIRWithShapeList : public WarpCacheIRBase {
const ShapeListSnapshot* shapes() const { return &shapes_; }
};
-// Like WarpCacheIR, but also includes a ShapeListWithOffsetsSnapshot for the
-// GuardMultipleShapesToOffset CacheIR op.
-class WarpCacheIRWithShapeListAndOffsets : public WarpCacheIRBase {
- const ShapeListWithOffsetsSnapshot shapes_;
-
- public:
- static constexpr Kind ThisKind = Kind::WarpCacheIRWithShapeListAndOffsets;
-
- WarpCacheIRWithShapeListAndOffsets(uint32_t offset, JitCode* stubCode,
- const CacheIRStubInfo* stubInfo,
- const uint8_t* stubData,
- const ShapeListWithOffsetsSnapshot& shapes)
- : WarpCacheIRBase(ThisKind, offset, stubCode, stubInfo, stubData),
- shapes_(shapes) {}
-
- void traceData(JSTracer* trc);
-
-#ifdef JS_JITSPEW
- void dumpData(GenericPrinter& out) const;
-#endif
-
- const ShapeListWithOffsetsSnapshot* shapes() const { return &shapes_; }
-};
-
// [SMDOC] Warp Nursery Object/Value support
//
// CacheIR stub data can contain nursery allocated objects or values. This can