Skip to content

Commit ebe50f0

Browse files
julian-seward1jseward@mozilla.com
authored andcommitted
Bug 1986850 - wasm-gc: Improve precision of alias-checking for structure loads/stores. r=bvisness,rhunt.
This improves alias checking for wasm wasm struct loads/stores, and has some ridealong cleanups for other wasm alias-set markings. * new method RefType::valuesMightAlias * new method MWasmLoadField::mightAlias, with helper StructTypesMightBeRelatedByInheritance, which adds some better checks for struct aliasing * ridealongs: - MWasmLoadField: set movable if there's no trap-site info - MWasmLoadField::congruentTo: tidy up (no functional change) * ridealongs: MWasmNeg, MWasmStackArg, WasmRegisterResult, WasmFloatRegisterResult, WasmBuiltinFloatRegisterResult, WasmRegister64Result, MWasmRefAsNonNull, WasmRefCastAbstract, WasmRefCastConcrete: add missing empty-alias-set annotations, as detected during testing * ridealong: MIROps.yaml: WasmBoundsCheckRange32: add missing `alias_set` of none and missing `guard` marking (the latter an outright bug) Differential Revision: https://phabricator.services.mozilla.com/D264039
1 parent cafbc72 commit ebe50f0

File tree

4 files changed

+90
-2
lines changed

4 files changed

+90
-2
lines changed

js/src/jit/MIR-wasm.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ class MWasmNeg : public MUnaryInstruction, public NoTypePolicy::Data {
579579
public:
580580
INSTRUCTION_HEADER(WasmNeg)
581581
TRIVIAL_NEW_WRAPPERS
582+
AliasSet getAliasSet() const override { return AliasSet::None(); }
582583
ALLOW_CLONE(MWasmNeg)
583584
};
584585

@@ -1635,6 +1636,10 @@ class MWasmParameter : public MNullaryInstruction {
16351636
public:
16361637
INSTRUCTION_HEADER(WasmParameter)
16371638
TRIVIAL_NEW_WRAPPERS
1639+
// MWasmParameter has no getAliasSet routine. Hence it acquires the default
1640+
// aliases-everything setting. This doesn't matter in practice because these
1641+
// nodes only appear at the start of the function's entry block, and in any
1642+
// case they are not marked as movable.
16381643

16391644
ABIArg abi() const { return abi_; }
16401645
};
@@ -1681,6 +1686,9 @@ class MWasmStackArg : public MUnaryInstruction, public NoTypePolicy::Data {
16811686

16821687
uint32_t spOffset() const { return spOffset_; }
16831688
void incrementOffset(uint32_t inc) { spOffset_ += inc; }
1689+
AliasSet getAliasSet() const override {
1690+
return AliasSet::Store(AliasSet::Flag::Any);
1691+
}
16841692

16851693
ALLOW_CLONE(MWasmStackArg)
16861694
};
@@ -1710,6 +1718,7 @@ class MWasmRegisterResult : public MWasmResultBase<Register> {
17101718
public:
17111719
INSTRUCTION_HEADER(WasmRegisterResult)
17121720
TRIVIAL_NEW_WRAPPERS
1721+
AliasSet getAliasSet() const override { return AliasSet::None(); }
17131722
};
17141723

17151724
class MWasmFloatRegisterResult : public MWasmResultBase<FloatRegister> {
@@ -1719,6 +1728,7 @@ class MWasmFloatRegisterResult : public MWasmResultBase<FloatRegister> {
17191728
public:
17201729
INSTRUCTION_HEADER(WasmFloatRegisterResult)
17211730
TRIVIAL_NEW_WRAPPERS
1731+
AliasSet getAliasSet() const override { return AliasSet::None(); }
17221732
};
17231733

17241734
class MWasmBuiltinFloatRegisterResult : public MWasmResultBase<FloatRegister> {
@@ -1730,6 +1740,7 @@ class MWasmBuiltinFloatRegisterResult : public MWasmResultBase<FloatRegister> {
17301740
public:
17311741
INSTRUCTION_HEADER(WasmBuiltinFloatRegisterResult)
17321742
TRIVIAL_NEW_WRAPPERS
1743+
AliasSet getAliasSet() const override { return AliasSet::None(); }
17331744

17341745
bool hardFP() const { return hardFP_; }
17351746
};
@@ -1741,6 +1752,7 @@ class MWasmRegister64Result : public MWasmResultBase<Register64> {
17411752
public:
17421753
INSTRUCTION_HEADER(WasmRegister64Result)
17431754
TRIVIAL_NEW_WRAPPERS
1755+
AliasSet getAliasSet() const override { return AliasSet::None(); }
17441756
};
17451757

17461758
class MWasmStackResultArea : public MNullaryInstruction {
@@ -2559,7 +2571,10 @@ class MWasmLoadField : public MBinaryInstruction, public NoTypePolicy::Data {
25592571
aliases.flags() == AliasSet::Load(AliasSet::Any).flags());
25602572
setResultType(type);
25612573
if (maybeTrap_) {
2574+
// This is safe, but see bug 1992059 for associated details.
25622575
setGuard();
2576+
} else {
2577+
setMovable();
25632578
}
25642579
initWasmRefType(maybeRefType);
25652580
}
@@ -2585,14 +2600,15 @@ class MWasmLoadField : public MBinaryInstruction, public NoTypePolicy::Data {
25852600
return false;
25862601
}
25872602
const MWasmLoadField* other = ins->toWasmLoadField();
2588-
return ins->isWasmLoadField() && congruentIfOperandsEqual(ins) &&
2589-
offset() == other->offset() &&
2603+
return congruentIfOperandsEqual(other) && offset() == other->offset() &&
25902604
structFieldIndex() == other->structFieldIndex() &&
25912605
wideningOp() == other->wideningOp() &&
25922606
getAliasSet().flags() == other->getAliasSet().flags() &&
25932607
hierarchy() == other->hierarchy();
25942608
}
25952609

2610+
virtual AliasType mightAlias(const MDefinition* ins) const override;
2611+
25962612
#ifdef JS_JITSPEW
25972613
void getExtras(ExtrasCollector* extras) const override {
25982614
char buf[96];
@@ -2954,6 +2970,7 @@ class MWasmRefAsNonNull : public MUnaryInstruction, public NoTypePolicy::Data {
29542970
}
29552971

29562972
MDefinition* foldsTo(TempAllocator& alloc) override;
2973+
AliasSet getAliasSet() const override { return AliasSet::None(); }
29572974

29582975
ALLOW_CLONE(MWasmRefAsNonNull)
29592976
};
@@ -3061,6 +3078,7 @@ class MWasmRefCastAbstract : public MUnaryInstruction,
30613078
INSTRUCTION_HEADER(WasmRefCastAbstract)
30623079
TRIVIAL_NEW_WRAPPERS
30633080
NAMED_OPERANDS((0, ref))
3081+
AliasSet getAliasSet() const override { return AliasSet::None(); }
30643082

30653083
wasm::RefType destType() const { return destType_; };
30663084
const wasm::TrapSiteDesc& trapSiteDesc() const { return trapSiteDesc_; }
@@ -3095,6 +3113,7 @@ class MWasmRefCastConcrete : public MBinaryInstruction,
30953113
INSTRUCTION_HEADER(WasmRefCastConcrete)
30963114
TRIVIAL_NEW_WRAPPERS
30973115
NAMED_OPERANDS((0, ref), (1, superSTV))
3116+
AliasSet getAliasSet() const override { return AliasSet::None(); }
30983117

30993118
wasm::RefType destType() const { return destType_; };
31003119
const wasm::TrapSiteDesc& trapSiteDesc() const { return trapSiteDesc_; }

js/src/jit/MIR.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8324,3 +8324,59 @@ bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const {
83248324
}
83258325
return congruentIfOperandsEqual(ins);
83268326
}
8327+
8328+
// Returns `false` if it can be proven that (1) both `mtyA` and `mtyB` are
8329+
// struct types and (2) they are not related by inheritance. Returns `true` in
8330+
// all other cases. `true` is the safe-but-possibly-suboptimal return value.
8331+
static bool StructTypesMightBeRelatedByInheritance(wasm::MaybeRefType mtyA,
8332+
wasm::MaybeRefType mtyB) {
8333+
if (!mtyA.isSome() || !mtyB.isSome()) {
8334+
// The "Track Wasm ref types" pass couldn't establish that both `mtyA` and
8335+
// `mtyB` are ref types. Give up.
8336+
return true;
8337+
}
8338+
8339+
wasm::RefType tyA = mtyA.value();
8340+
wasm::RefType tyB = mtyB.value();
8341+
if (!tyA.isTypeRef() || !tyA.typeDef()->isStructType() || !tyB.isTypeRef() ||
8342+
!tyB.typeDef()->isStructType()) {
8343+
// They aren't both struct types. Give up.
8344+
return true;
8345+
}
8346+
8347+
// They are both struct types. So they are related by inheritance if one is
8348+
// a subtype of the other. (Which is also the case if they are the same
8349+
// type.)
8350+
return wasm::RefType::valuesMightAlias(tyA, tyB);
8351+
}
8352+
8353+
MDefinition::AliasType MWasmLoadField::mightAlias(
8354+
const MDefinition* ins) const {
8355+
if (!(getAliasSet().flags() & ins->getAliasSet().flags())) {
8356+
return AliasType::NoAlias;
8357+
}
8358+
MOZ_ASSERT(!isEffectful() && ins->isEffectful());
8359+
8360+
// Pick off cases where we can easily prove non-aliasing. The idea is that
8361+
// two struct field accesses can't alias if either they are at different
8362+
// offsets, or the struct types are unrelated (which implies that the struct
8363+
// base pointer for one of the accesses could not validly be handed to the
8364+
// other access).
8365+
if (ins->isWasmStoreField()) {
8366+
const MWasmStoreField* store = ins->toWasmStoreField();
8367+
if (offset() != store->offset() ||
8368+
!StructTypesMightBeRelatedByInheritance(base()->wasmRefType(),
8369+
store->base()->wasmRefType())) {
8370+
return AliasType::NoAlias;
8371+
}
8372+
} else if (ins->isWasmStoreFieldRef()) {
8373+
const MWasmStoreFieldRef* store = ins->toWasmStoreFieldRef();
8374+
if (offset() != store->offset() ||
8375+
!StructTypesMightBeRelatedByInheritance(base()->wasmRefType(),
8376+
store->base()->wasmRefType())) {
8377+
return AliasType::NoAlias;
8378+
}
8379+
}
8380+
8381+
return AliasType::MayAlias;
8382+
}

js/src/jit/MIROps.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,6 +3957,8 @@
39573957
type_policy: none
39583958
generate_lir: true
39593959
lir_temps: 1
3960+
alias_set: none
3961+
guard: true
39603962

39613963
- name: WasmExtendU32Index
39623964
operands:

js/src/wasm/WasmValType.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,17 @@ class RefType {
444444
static bool isSubTypeOf(RefType subType, RefType superType);
445445
static bool castPossible(RefType sourceType, RefType destType);
446446

447+
// If we have two references, one of type `a` and one of type `b`, return
448+
// true if there is any possibility that they might point at the same thing.
449+
// That can only happen if either they are the same type or if one type is a
450+
// subtype of the other. Note, this can only be used for types in the same
451+
// hierarchy.
452+
static bool valuesMightAlias(RefType a, RefType b) {
453+
MOZ_RELEASE_ASSERT(a.hierarchy() == b.hierarchy());
454+
// The exact-same-type case is subsumed by `isSubTypeOf`.
455+
return RefType::isSubTypeOf(a, b) || RefType::isSubTypeOf(b, a);
456+
}
457+
447458
// Gets the top of the given type's hierarchy, e.g. Any for structs and
448459
// arrays, and Func for funcs.
449460
RefType topType() const;

0 commit comments

Comments
 (0)