mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1814519 - wasm: Don't emit pre-write barrier for initialization of structs/arrays. r=jseward
Arrays/structs are initialized to be completely null. The pre-write barrier will always be dead code for them. Differential Revision: https://phabricator.services.mozilla.com/D168618
This commit is contained in:
parent
528f75b536
commit
34a2ac98fd
@ -150,6 +150,14 @@ struct FunctionCall {
|
|||||||
size_t stackArgAreaSize;
|
size_t stackArgAreaSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PreBarrierKind {
|
||||||
|
// No pre-write barrier is required because the previous value is undefined.
|
||||||
|
None,
|
||||||
|
// Perform a pre-write barrier to mark the previous value if an incremental
|
||||||
|
// GC is underway.
|
||||||
|
Normal,
|
||||||
|
};
|
||||||
|
|
||||||
enum class PostBarrierKind {
|
enum class PostBarrierKind {
|
||||||
// Remove an existing store buffer entry if the new value does not require
|
// Remove an existing store buffer entry if the new value does not require
|
||||||
// one. This is required to preserve invariants with HeapPtr when used for
|
// one. This is required to preserve invariants with HeapPtr when used for
|
||||||
@ -1306,7 +1314,8 @@ struct BaseCompiler final {
|
|||||||
// Preserves `object` and `value`. Consumes `valueAddr`.
|
// Preserves `object` and `value`. Consumes `valueAddr`.
|
||||||
[[nodiscard]] bool emitBarrieredStore(const Maybe<RegRef>& object,
|
[[nodiscard]] bool emitBarrieredStore(const Maybe<RegRef>& object,
|
||||||
RegPtr valueAddr, RegRef value,
|
RegPtr valueAddr, RegRef value,
|
||||||
PostBarrierKind kind);
|
PreBarrierKind preBarrierKind,
|
||||||
|
PostBarrierKind postBarrierKind);
|
||||||
|
|
||||||
// Emits a store of nullptr to a JS object pointer at the address valueAddr.
|
// Emits a store of nullptr to a JS object pointer at the address valueAddr.
|
||||||
// Preserves `valueAddr`.
|
// Preserves `valueAddr`.
|
||||||
@ -1683,10 +1692,12 @@ struct BaseCompiler final {
|
|||||||
template <typename NullCheckPolicy>
|
template <typename NullCheckPolicy>
|
||||||
[[nodiscard]] bool emitGcStructSet(RegRef object, RegPtr areaBase,
|
[[nodiscard]] bool emitGcStructSet(RegRef object, RegPtr areaBase,
|
||||||
uint32_t areaOffset, FieldType fieldType,
|
uint32_t areaOffset, FieldType fieldType,
|
||||||
AnyReg value);
|
AnyReg value,
|
||||||
|
PreBarrierKind preBarrierKind);
|
||||||
|
|
||||||
[[nodiscard]] bool emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
[[nodiscard]] bool emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
||||||
const ArrayType& array, AnyReg value);
|
const ArrayType& array, AnyReg value,
|
||||||
|
PreBarrierKind preBarrierKind);
|
||||||
#endif // ENABLE_WASM_GC
|
#endif // ENABLE_WASM_GC
|
||||||
|
|
||||||
#ifdef ENABLE_WASM_SIMD
|
#ifdef ENABLE_WASM_SIMD
|
||||||
|
@ -4465,6 +4465,7 @@ bool BaseCompiler::emitThrow() {
|
|||||||
pushPtr(data);
|
pushPtr(data);
|
||||||
// emitBarrieredStore preserves exn, rv
|
// emitBarrieredStore preserves exn, rv
|
||||||
if (!emitBarrieredStore(Some(exn), valueAddr, rv,
|
if (!emitBarrieredStore(Some(exn), valueAddr, rv,
|
||||||
|
PreBarrierKind::Normal,
|
||||||
PostBarrierKind::Imprecise)) {
|
PostBarrierKind::Imprecise)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5380,7 +5381,7 @@ bool BaseCompiler::emitSetGlobal() {
|
|||||||
}
|
}
|
||||||
RegRef rv = popRef();
|
RegRef rv = popRef();
|
||||||
// emitBarrieredStore preserves rv
|
// emitBarrieredStore preserves rv
|
||||||
if (!emitBarrieredStore(Nothing(), valueAddr, rv,
|
if (!emitBarrieredStore(Nothing(), valueAddr, rv, PreBarrierKind::Normal,
|
||||||
PostBarrierKind::Imprecise)) {
|
PostBarrierKind::Imprecise)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6194,7 +6195,7 @@ bool BaseCompiler::emitTableSetAnyRef(uint32_t tableIndex) {
|
|||||||
value = popRef();
|
value = popRef();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!emitBarrieredStore(Nothing(), valueAddr, value,
|
if (!emitBarrieredStore(Nothing(), valueAddr, value, PreBarrierKind::Normal,
|
||||||
PostBarrierKind::Precise)) {
|
PostBarrierKind::Precise)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6310,18 +6311,21 @@ bool BaseCompiler::emitPostBarrierPrecise(const Maybe<RegRef>& object,
|
|||||||
|
|
||||||
bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
|
bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
|
||||||
RegPtr valueAddr, RegRef value,
|
RegPtr valueAddr, RegRef value,
|
||||||
PostBarrierKind kind) {
|
PreBarrierKind preBarrierKind,
|
||||||
|
PostBarrierKind postBarrierKind) {
|
||||||
// TODO/AnyRef-boxing: With boxed immediates and strings, the write
|
// TODO/AnyRef-boxing: With boxed immediates and strings, the write
|
||||||
// barrier is going to have to be more complicated.
|
// barrier is going to have to be more complicated.
|
||||||
ASSERT_ANYREF_IS_JSOBJECT;
|
ASSERT_ANYREF_IS_JSOBJECT;
|
||||||
|
|
||||||
// The pre-barrier preserves all allocated registers.
|
// The pre-barrier preserves all allocated registers.
|
||||||
emitPreBarrier(valueAddr);
|
if (preBarrierKind == PreBarrierKind::Normal) {
|
||||||
|
emitPreBarrier(valueAddr);
|
||||||
|
}
|
||||||
|
|
||||||
// The precise post-barrier requires the previous value stored in the field,
|
// The precise post-barrier requires the previous value stored in the field,
|
||||||
// in order to know if the previous store buffer entry needs to be removed.
|
// in order to know if the previous store buffer entry needs to be removed.
|
||||||
RegRef prevValue;
|
RegRef prevValue;
|
||||||
if (kind == PostBarrierKind::Precise) {
|
if (postBarrierKind == PostBarrierKind::Precise) {
|
||||||
prevValue = needRef();
|
prevValue = needRef();
|
||||||
masm.loadPtr(Address(valueAddr, 0), prevValue);
|
masm.loadPtr(Address(valueAddr, 0), prevValue);
|
||||||
}
|
}
|
||||||
@ -6330,7 +6334,7 @@ bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
|
|||||||
masm.storePtr(value, Address(valueAddr, 0));
|
masm.storePtr(value, Address(valueAddr, 0));
|
||||||
|
|
||||||
// The post-barrier preserves object and value.
|
// The post-barrier preserves object and value.
|
||||||
if (kind == PostBarrierKind::Precise) {
|
if (postBarrierKind == PostBarrierKind::Precise) {
|
||||||
return emitPostBarrierPrecise(object, valueAddr, prevValue, value);
|
return emitPostBarrierPrecise(object, valueAddr, prevValue, value);
|
||||||
}
|
}
|
||||||
return emitPostBarrierImprecise(object, valueAddr, value);
|
return emitPostBarrierImprecise(object, valueAddr, value);
|
||||||
@ -6580,7 +6584,8 @@ void BaseCompiler::emitGcSetScalar(const T& dst, FieldType type, AnyReg value) {
|
|||||||
template <typename NullCheckPolicy>
|
template <typename NullCheckPolicy>
|
||||||
bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr areaBase,
|
bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr areaBase,
|
||||||
uint32_t areaOffset, FieldType fieldType,
|
uint32_t areaOffset, FieldType fieldType,
|
||||||
AnyReg value) {
|
AnyReg value,
|
||||||
|
PreBarrierKind preBarrierKind) {
|
||||||
// Easy path if the field is a scalar
|
// Easy path if the field is a scalar
|
||||||
if (!fieldType.isRefRepr()) {
|
if (!fieldType.isRefRepr()) {
|
||||||
emitGcSetScalar<Address, NullCheckPolicy>(Address(areaBase, areaOffset),
|
emitGcSetScalar<Address, NullCheckPolicy>(Address(areaBase, areaOffset),
|
||||||
@ -6598,7 +6603,7 @@ bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr areaBase,
|
|||||||
NullCheckPolicy::emitNullCheck(this, object);
|
NullCheckPolicy::emitNullCheck(this, object);
|
||||||
|
|
||||||
// emitBarrieredStore preserves object and value
|
// emitBarrieredStore preserves object and value
|
||||||
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(),
|
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(), preBarrierKind,
|
||||||
PostBarrierKind::Imprecise)) {
|
PostBarrierKind::Imprecise)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6608,7 +6613,8 @@ bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr areaBase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
||||||
const ArrayType& arrayType, AnyReg value) {
|
const ArrayType& arrayType, AnyReg value,
|
||||||
|
PreBarrierKind preBarrierKind) {
|
||||||
// Try to use a base index store instruction if the field type fits in a
|
// Try to use a base index store instruction if the field type fits in a
|
||||||
// shift immediate. If not we shift the index manually and then unshift
|
// shift immediate. If not we shift the index manually and then unshift
|
||||||
// it after the store. We don't use an extra register for this because we
|
// it after the store. We don't use an extra register for this because we
|
||||||
@ -6647,7 +6653,7 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
|||||||
pushI32(index);
|
pushI32(index);
|
||||||
|
|
||||||
// emitBarrieredStore preserves object and value
|
// emitBarrieredStore preserves object and value
|
||||||
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(),
|
if (!emitBarrieredStore(Some(object), valueAddr, value.ref(), preBarrierKind,
|
||||||
PostBarrierKind::Imprecise)) {
|
PostBarrierKind::Imprecise)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -6736,7 +6742,8 @@ bool BaseCompiler::emitStructNew() {
|
|||||||
|
|
||||||
// Consumes value and outline data, object is preserved by this call.
|
// Consumes value and outline data, object is preserved by this call.
|
||||||
if (!emitGcStructSet<NoNullCheck>(object, outlineBase, areaOffset,
|
if (!emitGcStructSet<NoNullCheck>(object, outlineBase, areaOffset,
|
||||||
fieldType, value)) {
|
fieldType, value,
|
||||||
|
PreBarrierKind::None)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -6744,7 +6751,7 @@ bool BaseCompiler::emitStructNew() {
|
|||||||
if (!emitGcStructSet<NoNullCheck>(
|
if (!emitGcStructSet<NoNullCheck>(
|
||||||
object, RegPtr(object),
|
object, RegPtr(object),
|
||||||
WasmStructObject::offsetOfInlineData() + areaOffset, fieldType,
|
WasmStructObject::offsetOfInlineData() + areaOffset, fieldType,
|
||||||
value)) {
|
value, PreBarrierKind::None)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6862,7 +6869,8 @@ bool BaseCompiler::emitStructSet() {
|
|||||||
masm.loadPtr(Address(object, WasmStructObject::offsetOfOutlineData()),
|
masm.loadPtr(Address(object, WasmStructObject::offsetOfOutlineData()),
|
||||||
outlineBase);
|
outlineBase);
|
||||||
if (!emitGcStructSet<NoNullCheck>(object, outlineBase, areaOffset,
|
if (!emitGcStructSet<NoNullCheck>(object, outlineBase, areaOffset,
|
||||||
fieldType, value)) {
|
fieldType, value,
|
||||||
|
PreBarrierKind::Normal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -6870,7 +6878,7 @@ bool BaseCompiler::emitStructSet() {
|
|||||||
if (!emitGcStructSet<SignalNullCheck>(
|
if (!emitGcStructSet<SignalNullCheck>(
|
||||||
object, RegPtr(object),
|
object, RegPtr(object),
|
||||||
WasmStructObject::offsetOfInlineData() + areaOffset, fieldType,
|
WasmStructObject::offsetOfInlineData() + areaOffset, fieldType,
|
||||||
value)) {
|
value, PreBarrierKind::Normal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6935,7 +6943,8 @@ bool BaseCompiler::emitArrayNew() {
|
|||||||
masm.sub32(Imm32(1), numElements);
|
masm.sub32(Imm32(1), numElements);
|
||||||
|
|
||||||
// Assign value to array[numElements]. All registers are preserved
|
// Assign value to array[numElements]. All registers are preserved
|
||||||
if (!emitGcArraySet(rp, rdata, numElements, arrayType, value)) {
|
if (!emitGcArraySet(rp, rdata, numElements, arrayType, value,
|
||||||
|
PreBarrierKind::None)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7013,7 +7022,8 @@ bool BaseCompiler::emitArrayNewFixed() {
|
|||||||
if (avoidPreBarrierReg) {
|
if (avoidPreBarrierReg) {
|
||||||
freePtr(RegPtr(PreBarrierReg));
|
freePtr(RegPtr(PreBarrierReg));
|
||||||
}
|
}
|
||||||
if (!emitGcArraySet(rp, rdata, index, arrayType, value)) {
|
if (!emitGcArraySet(rp, rdata, index, arrayType, value,
|
||||||
|
PreBarrierKind::None)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
freeI32(index);
|
freeI32(index);
|
||||||
@ -7169,7 +7179,8 @@ bool BaseCompiler::emitArraySet() {
|
|||||||
// All registers are preserved. This isn't strictly necessary, as we'll just
|
// All registers are preserved. This isn't strictly necessary, as we'll just
|
||||||
// be freeing them all after this is done. But this is needed for repeated
|
// be freeing them all after this is done. But this is needed for repeated
|
||||||
// assignments used in array.new/new_default.
|
// assignments used in array.new/new_default.
|
||||||
if (!emitGcArraySet(rp, rdata, index, arrayType, value)) {
|
if (!emitGcArraySet(rp, rdata, index, arrayType, value,
|
||||||
|
PreBarrierKind::Normal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user