Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Current Trunk
argument `optimize`. (#4832)
- Remove support for the `let` instruction that has been removed from the typed
function references spec.
- HeapType::ext has been restored but is no longer a subtype of HeapType::any to
match the latest updates in the GC spec. (#4898)

v109
----
Expand Down
10 changes: 7 additions & 3 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
case HeapType::func:
ret.func = x.isNull() ? nullptr : x.getFunc().c_str();
break;
case HeapType::any:
case HeapType::ext:
case HeapType::eq:
assert(x.isNull() && "unexpected non-null reference type literal");
break;
case HeapType::any:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is any's behavior here different from that of ext? Is any not nullable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only support the standardized reference types extern and func in this API and all the GC types are meant to hit that WASM_UNREACHABLE. Previously HeapType::any represented the standardized extern, but now it only represents the sepate any GC type.

case HeapType::i31:
case HeapType::data:
case HeapType::string:
Expand Down Expand Up @@ -113,6 +114,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
case HeapType::data:
assert(false && "Literals must have concrete types");
WASM_UNREACHABLE("no fallthrough here");
case HeapType::ext:
case HeapType::i31:
case HeapType::string:
case HeapType::stringview_wtf8:
Expand Down Expand Up @@ -158,7 +160,6 @@ extern "C" {
//

// Core types
// TODO: Deprecate BinaryenTypeExternref?

BinaryenType BinaryenTypeNone(void) { return Type::none; }
BinaryenType BinaryenTypeInt32(void) { return Type::i32; }
Expand All @@ -170,7 +171,7 @@ BinaryenType BinaryenTypeFuncref(void) {
return Type(HeapType::func, Nullable).getID();
}
BinaryenType BinaryenTypeExternref(void) {
return Type(HeapType::any, Nullable).getID();
return Type(HeapType::ext, Nullable).getID();
}
BinaryenType BinaryenTypeAnyref(void) {
return Type(HeapType::any, Nullable).getID();
Expand Down Expand Up @@ -239,6 +240,9 @@ BinaryenPackedType BinaryenPackedTypeInt16(void) {

// Heap types

BinaryenHeapType BinaryenHeapTypeExt() {
return static_cast<BinaryenHeapType>(HeapType::BasicHeapType::ext);
}
BinaryenHeapType BinaryenHeapTypeFunc() {
return static_cast<BinaryenHeapType>(HeapType::BasicHeapType::func);
}
Expand Down
1 change: 1 addition & 0 deletions src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ BINARYEN_API BinaryenPackedType BinaryenPackedTypeInt16(void);

typedef uintptr_t BinaryenHeapType;

BINARYEN_API BinaryenHeapType BinaryenHeapTypeExt(void);
BINARYEN_API BinaryenHeapType BinaryenHeapTypeFunc(void);
BINARYEN_API BinaryenHeapType BinaryenHeapTypeAny(void);
BINARYEN_API BinaryenHeapType BinaryenHeapTypeEq(void);
Expand Down
10 changes: 8 additions & 2 deletions src/ir/possible-constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,14 @@ struct PossibleConstantValues {
auto type = getConstantLiteral().type.getHeapType();
auto otherType = other.getConstantLiteral().type.getHeapType();
auto lub = HeapType::getLeastUpperBound(type, otherType);
if (lub != type) {
value = Literal::makeNull(lub);
if (!lub) {
// TODO: Remove this workaround once we have bottom types to assign to
// null literals.
value = Many();
return true;
}
if (*lub != type) {
value = Literal::makeNull(*lub);
return true;
}
return false;
Expand Down
8 changes: 7 additions & 1 deletion src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ void PossibleContents::combine(const PossibleContents& other) {
assert(other.isNull());
auto lub = HeapType::getLeastUpperBound(type.getHeapType(),
otherType.getHeapType());
value = Literal::makeNull(lub);
if (!lub) {
// TODO: Remove this workaround once we have bottom types to assign to
// null literals.
value = Many();
return;
}
value = Literal::makeNull(*lub);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, this can make a Many().

}
return;
}
Expand Down
18 changes: 9 additions & 9 deletions src/passes/InstrumentLocals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ Name get_f32("get_f32");
Name get_f64("get_f64");
Name get_v128("get_v128");
Name get_funcref("get_funcref");
Name get_anyref("get_anyref");
Name get_externref("get_externref");

Name set_i32("set_i32");
Name set_i64("set_i64");
Name set_f32("set_f32");
Name set_f64("set_f64");
Name set_v128("set_v128");
Name set_funcref("set_funcref");
Name set_anyref("set_anyref");
Name set_externref("set_externref");

struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
void visitLocalGet(LocalGet* curr) {
Expand All @@ -75,8 +75,8 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
auto heapType = curr->type.getHeapType();
if (heapType == HeapType::func && curr->type.isNullable()) {
import = get_funcref;
} else if (heapType == HeapType::any && curr->type.isNullable()) {
import = get_anyref;
} else if (heapType == HeapType::ext && curr->type.isNullable()) {
import = get_externref;
} else {
WASM_UNREACHABLE("TODO: general reference types");
}
Expand Down Expand Up @@ -128,8 +128,8 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
auto heapType = type.getHeapType();
if (heapType == HeapType::func && type.isNullable()) {
import = set_funcref;
} else if (heapType == HeapType::any && type.isNullable()) {
import = set_anyref;
} else if (heapType == HeapType::ext && type.isNullable()) {
import = set_externref;
} else {
WASM_UNREACHABLE("TODO: general reference types");
}
Expand Down Expand Up @@ -175,12 +175,12 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {

if (curr->features.hasReferenceTypes()) {
Type func = Type(HeapType::func, Nullable);
Type any = Type(HeapType::any, Nullable);
Type ext = Type(HeapType::ext, Nullable);

addImport(curr, get_funcref, {Type::i32, Type::i32, func}, func);
addImport(curr, set_funcref, {Type::i32, Type::i32, func}, func);
addImport(curr, get_anyref, {Type::i32, Type::i32, any}, any);
addImport(curr, set_anyref, {Type::i32, Type::i32, any}, any);
addImport(curr, get_externref, {Type::i32, Type::i32, ext}, ext);
addImport(curr, set_externref, {Type::i32, Type::i32, ext}, ext);
}
if (curr->features.hasSIMD()) {
addImport(curr, get_v128, {Type::i32, Type::i32, Type::v128}, Type::v128);
Expand Down
4 changes: 4 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ static bool maybePrintRefShorthand(std::ostream& o, Type type) {
if (heapType.isBasic()) {
if (type.isNullable()) {
switch (heapType.getBasic()) {
case HeapType::ext:
o << "externref";
return true;
case HeapType::func:
o << "funcref";
return true;
Expand Down Expand Up @@ -107,6 +110,7 @@ static bool maybePrintRefShorthand(std::ostream& o, Type type) {
}
} else {
switch (heapType.getBasic()) {
case HeapType::ext:
case HeapType::func:
case HeapType::any:
case HeapType::eq:
Expand Down
9 changes: 7 additions & 2 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,10 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) {
assert(heapType.isBasic());
assert(wasm.features.hasReferenceTypes());
switch (heapType.getBasic()) {
case HeapType::ext: {
assert(type.isNullable() && "Cannot handle non-nullable externref");
return builder.makeRefNull(type);
}
case HeapType::func: {
return makeRefFuncConst(type);
}
Expand Down Expand Up @@ -3024,13 +3028,14 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) {
case HeapType::func:
// TODO: Typed function references.
return HeapType::func;
case HeapType::ext:
return HeapType::ext;
case HeapType::any:
// TODO: nontrivial types as well.
return pick(
FeatureOptions<HeapType>()
.add(FeatureSet::ReferenceTypes, HeapType::func, HeapType::any)
.add(FeatureSet::ReferenceTypes, HeapType::func /*, HeapType::ext*/)
.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
HeapType::func,
HeapType::any,
HeapType::eq,
HeapType::i31,
Expand Down
27 changes: 23 additions & 4 deletions src/tools/fuzzing/heap-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ struct HeapTypeGeneratorImpl {

HeapType::BasicHeapType generateBasicHeapType() {
return rand.pick(HeapType::func,
HeapType::ext,
HeapType::any,
HeapType::eq,
HeapType::i31,
Expand Down Expand Up @@ -278,6 +279,7 @@ struct HeapTypeGeneratorImpl {
return type;
} else {
switch (type) {
case HeapType::ext:
case HeapType::i31:
// No other subtypes.
return type;
Expand Down Expand Up @@ -371,6 +373,8 @@ struct HeapTypeGeneratorImpl {
// This is not a constructed type, so it must be a basic type.
assert(type.isBasic());
switch (type.getBasic()) {
case HeapType::ext:
return HeapType::ext;
case HeapType::func:
return pickSubFunc();
case HeapType::any:
Expand Down Expand Up @@ -477,16 +481,31 @@ struct HeapTypeGeneratorImpl {
switch (*basic) {
case HeapType::func:
return SignatureKind{};
case HeapType::ext:
case HeapType::i31:
return super;
case HeapType::any:
return generateHeapTypeKind();
if (rand.oneIn(4)) {
switch (rand.upTo(3)) {
case 0:
return HeapType::eq;
case 1:
return HeapType::i31;
case 2:
return HeapType::data;
}
}
return DataKind{};
case HeapType::eq:
if (rand.oneIn(4)) {
return HeapType::i31;
} else {
return DataKind{};
switch (rand.upTo(2)) {
case 0:
return HeapType::i31;
case 1:
return HeapType::data;
}
}
return DataKind{};
case HeapType::data:
return DataKind{};
case HeapType::string:
Expand Down
106 changes: 66 additions & 40 deletions src/tools/wasm-fuzz-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,46 +152,72 @@ void Fuzzer::checkLUBs() const {
HeapType a = types[i], b = types[j];
// Check that their LUB is stable when calculated multiple times and in
// reverse order.
HeapType lub = HeapType::getLeastUpperBound(a, b);
if (lub != HeapType::getLeastUpperBound(b, a) ||
lub != HeapType::getLeastUpperBound(a, b)) {
Fatal() << "Could not calculate a stable LUB of HeapTypes " << i
<< " and " << j << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n";
}
// Check that each type is a subtype of the LUB.
if (!HeapType::isSubType(a, lub)) {
Fatal() << "HeapType " << i
<< " is not a subtype of its LUB with HeapType " << j << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << lub << "\n";
}
if (!HeapType::isSubType(b, lub)) {
Fatal() << "HeapType " << j
<< " is not a subtype of its LUB with HeapType " << i << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << lub << "\n";
}
// Check that the LUB of each type and the original LUB is still the
// original LUB.
if (lub != HeapType::getLeastUpperBound(a, lub)) {
Fatal() << "The LUB of HeapType " << i << " and HeapType " << j
<< " should be the LUB of itself and HeapType " << i
<< ", but it is not!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << lub << "\n";
}
if (lub != HeapType::getLeastUpperBound(lub, b)) {
Fatal() << "The LUB of HeapType " << i << " and HeapType " << j
<< " should be the LUB of itself and HeapType " << j
<< ", but it is not!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << lub << "\n";
auto lub = HeapType::getLeastUpperBound(a, b);
if (lub) {
if (lub != HeapType::getLeastUpperBound(b, a) ||
lub != HeapType::getLeastUpperBound(a, b)) {
Fatal() << "Could not calculate a stable LUB of HeapTypes " << i
<< " and " << j << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n";
}
// Check that each type is a subtype of the LUB.
if (!HeapType::isSubType(a, *lub)) {
Fatal() << "HeapType " << i
<< " is not a subtype of its LUB with HeapType " << j << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << *lub << "\n";
}
if (!HeapType::isSubType(b, *lub)) {
Fatal() << "HeapType " << j
<< " is not a subtype of its LUB with HeapType " << i << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << *lub << "\n";
}
// Check that the LUB of each type and the original LUB is still the
// original LUB.
if (lub != HeapType::getLeastUpperBound(a, *lub)) {
Fatal() << "The LUB of HeapType " << i << " and HeapType " << j
<< " should be the LUB of itself and HeapType " << i
<< ", but it is not!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << *lub << "\n";
}
if (lub != HeapType::getLeastUpperBound(*lub, b)) {
Fatal() << "The LUB of HeapType " << i << " and HeapType " << j
<< " should be the LUB of itself and HeapType " << j
<< ", but it is not!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << *lub << "\n";
}
} else {
// No LUB. Check that this is symmetrical.
if (auto lub2 = HeapType::getLeastUpperBound(b, a)) {
Fatal() << "There is no LUB of HeapType " << i << " and HeapType "
<< j << ", but there is a LUB in the reverse direction!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n"
<< "lub: " << *lub2 << "\n";
}
// There also shouldn't be a subtype relation in this case.
if (HeapType::isSubType(a, b)) {
Fatal() << "There is no LUB of HeapType " << i << " and HeapType "
<< j << ", but HeapType " << i << " is a subtype of HeapType "
<< j << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n";
}
if (HeapType::isSubType(b, a)) {
Fatal() << "There is no LUB of HeapType " << i << " and HeapType "
<< j << ", but HeapType " << j << " is a subtype of HeapType "
<< i << "!\n"
<< i << ": " << a << "\n"
<< j << ": " << b << "\n";
}
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,10 @@ enum EncodedType {
i16 = -0x7, // 0x79
// function reference type
funcref = -0x10, // 0x70
// top type of references, including host references
anyref = -0x11, // 0x6f
// external (host) references
externref = -0x11, // 0x6f
// top type of references to non-function Wasm data.
anyref = -0x12, // 0x6e
// comparable reference type
eqref = -0x13, // 0x6d
// nullable typed function reference type, with parameter
Expand Down Expand Up @@ -396,7 +398,8 @@ enum EncodedType {

enum EncodedHeapType {
func = -0x10, // 0x70
any = -0x11, // 0x6f
ext = -0x11, // 0x6f
any = -0x12, // 0x6e
eq = -0x13, // 0x6d
i31 = -0x16, // 0x6a
data = -0x19, // 0x67
Expand Down
Loading