summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Wirtz <dcode@dcode.io>2020-09-11 03:04:17 +0200
committerGitHub <noreply@github.com>2020-09-10 18:04:17 -0700
commit192757772adce7568fc1f3f3e733a4263b6392c6 (patch)
tree922fec8709cf9008d239a1fcbce7280e6ab46deb /src
parentcd6f0d908f0e4c68d72fd476a6e0e7cfb7ae8595 (diff)
downloadbinaryen-192757772adce7568fc1f3f3e733a4263b6392c6.tar.gz
binaryen-192757772adce7568fc1f3f3e733a4263b6392c6.tar.bz2
binaryen-192757772adce7568fc1f3f3e733a4263b6392c6.zip
Add anyref feature and type (#3109)
Adds `anyref` type, which is enabled by a new feature `--enable-anyref`. This type is primarily used for testing that passes correctly handle subtype relationships so that the codebase will continue to be prepared for future subtyping. Since `--enable-anyref` is meaningless without also using `--enable-reference-types`, this PR also makes it a validation error to pass only the former (and similarly makes it a validation error to enable exception handling without enabling reference types).
Diffstat (limited to 'src')
-rw-r--r--src/asmjs/asm_v_wasm.cpp3
-rw-r--r--src/binaryen-c.cpp6
-rw-r--r--src/binaryen-c.h2
-rw-r--r--src/gen-s-parser.inc18
-rw-r--r--src/ir/abstract.h2
-rw-r--r--src/js/binaryen.js-post.js8
-rw-r--r--src/literal.h1
-rw-r--r--src/parsing.h1
-rw-r--r--src/passes/ConstHoisting.cpp3
-rw-r--r--src/passes/FuncCastEmulation.cpp6
-rw-r--r--src/passes/InstrumentLocals.cpp26
-rw-r--r--src/shell-interface.h1
-rw-r--r--src/tools/fuzzing.h33
-rw-r--r--src/tools/spec-wrapper.h3
-rw-r--r--src/tools/tool-options.h1
-rw-r--r--src/tools/wasm-reduce.cpp5
-rw-r--r--src/wasm-binary.h9
-rw-r--r--src/wasm-builder.h2
-rw-r--r--src/wasm-features.h7
-rw-r--r--src/wasm-interpreter.h2
-rw-r--r--src/wasm-type.h15
-rw-r--r--src/wasm/literal.cpp14
-rw-r--r--src/wasm/wasm-binary.cpp8
-rw-r--r--src/wasm/wasm-s-parser.cpp3
-rw-r--r--src/wasm/wasm-stack.cpp3
-rw-r--r--src/wasm/wasm-type.cpp34
-rw-r--r--src/wasm/wasm-validator.cpp17
-rw-r--r--src/wasm/wasm.cpp1
28 files changed, 203 insertions, 31 deletions
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp
index ddcb27d3d..8d2894f13 100644
--- a/src/asmjs/asm_v_wasm.cpp
+++ b/src/asmjs/asm_v_wasm.cpp
@@ -57,6 +57,7 @@ AsmType wasmToAsmType(Type type) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
assert(false && "reference types are not supported by asm2wasm");
case Type::none:
return ASM_NONE;
@@ -85,6 +86,8 @@ char getSig(Type type) {
return 'X';
case Type::exnref:
return 'E';
+ case Type::anyref:
+ return 'A';
case Type::none:
return 'v';
case Type::unreachable:
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 9b2da350d..e11b762dd 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -73,6 +73,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
break;
case Type::externref:
case Type::exnref:
+ case Type::anyref:
assert(x.isNull());
break;
case Type::none:
@@ -98,6 +99,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
return Literal::makeFunc(x.func);
case Type::externref:
case Type::exnref:
+ case Type::anyref:
return Literal::makeNull(Type(x.type));
case Type::none:
case Type::unreachable:
@@ -133,6 +135,7 @@ BinaryenType BinaryenTypeVec128(void) { return Type::v128; }
BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; }
BinaryenType BinaryenTypeExternref(void) { return Type::externref; }
BinaryenType BinaryenTypeExnref(void) { return Type::exnref; }
+BinaryenType BinaryenTypeAnyref(void) { return Type::anyref; }
BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; }
BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); }
@@ -324,6 +327,9 @@ BinaryenFeatures BinaryenFeatureReferenceTypes(void) {
BinaryenFeatures BinaryenFeatureMultivalue(void) {
return static_cast<BinaryenFeatures>(FeatureSet::Multivalue);
}
+BinaryenFeatures BinaryenFeatureAnyref(void) {
+ return static_cast<BinaryenFeatures>(FeatureSet::Anyref);
+}
BinaryenFeatures BinaryenFeatureAll(void) {
return static_cast<BinaryenFeatures>(FeatureSet::All);
}
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index beaf72499..e622419ac 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -101,6 +101,7 @@ BINARYEN_API BinaryenType BinaryenTypeVec128(void);
BINARYEN_API BinaryenType BinaryenTypeFuncref(void);
BINARYEN_API BinaryenType BinaryenTypeExternref(void);
BINARYEN_API BinaryenType BinaryenTypeExnref(void);
+BINARYEN_API BinaryenType BinaryenTypeAnyref(void);
BINARYEN_API BinaryenType BinaryenTypeUnreachable(void);
// Not a real type. Used as the last parameter to BinaryenBlock to let
// the API figure out the type instead of providing one.
@@ -196,6 +197,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureExceptionHandling(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureTailCall(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureReferenceTypes(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureMultivalue(void);
+BINARYEN_API BinaryenFeatures BinaryenFeatureAnyref(void);
BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void);
// Modules
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 97ba15c32..4b02b09c2 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -8,13 +8,21 @@ char op[27] = {'\0'};
strncpy(op, s[0]->c_str(), 26);
switch (op[0]) {
case 'a': {
- switch (op[7]) {
- case 'f':
- if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); }
- goto parse_error;
+ switch (op[1]) {
case 'n':
- if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); }
+ if (strcmp(op, "anyref.pop") == 0) { return makePop(Type::anyref); }
goto parse_error;
+ case 't': {
+ switch (op[7]) {
+ case 'f':
+ if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); }
+ goto parse_error;
+ case 'n':
+ if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
diff --git a/src/ir/abstract.h b/src/ir/abstract.h
index b00537bf5..5f1fd393e 100644
--- a/src/ir/abstract.h
+++ b/src/ir/abstract.h
@@ -104,6 +104,7 @@ inline UnaryOp getUnary(Type type, Op op) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable: {
return InvalidUnary;
@@ -268,6 +269,7 @@ inline BinaryOp getBinary(Type type, Op op) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable: {
return InvalidBinary;
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index 66de10848..fd121b8af 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -36,6 +36,7 @@ function initializeConstants() {
['funcref', 'Funcref'],
['externref', 'Externref'],
['exnref', 'Exnref'],
+ ['anyref', 'Anyref'],
['unreachable', 'Unreachable'],
['auto', 'Auto']
].forEach(entry => {
@@ -120,6 +121,7 @@ function initializeConstants() {
'TailCall',
'ReferenceTypes',
'Multivalue',
+ 'Anyref',
'All'
].forEach(name => {
Module['Features'][name] = Module['_BinaryenFeature' + name]();
@@ -2063,6 +2065,12 @@ function wrapModule(module, self = {}) {
}
};
+ self['anyref'] = {
+ 'pop'() {
+ return Module['_BinaryenPop'](module, Module['anyref']);
+ }
+ };
+
self['ref'] = {
'null'(type) {
return Module['_BinaryenRefNull'](module, type);
diff --git a/src/literal.h b/src/literal.h
index 1b3949d21..981f5b6d4 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -579,6 +579,7 @@ template<> struct less<wasm::Literal> {
case wasm::Type::funcref:
case wasm::Type::externref:
case wasm::Type::exnref:
+ case wasm::Type::anyref:
case wasm::Type::none:
case wasm::Type::unreachable:
return false;
diff --git a/src/parsing.h b/src/parsing.h
index 663b901fd..d809cbedd 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -266,6 +266,7 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
WASM_UNREACHABLE("unexpected const type");
case Type::none:
case Type::unreachable: {
diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp
index e3583d3bb..3b34751ff 100644
--- a/src/passes/ConstHoisting.cpp
+++ b/src/passes/ConstHoisting.cpp
@@ -96,7 +96,8 @@ private:
case Type::v128:
case Type::funcref:
case Type::externref:
- case Type::exnref: {
+ case Type::exnref:
+ case Type::anyref: {
return false;
}
case Type::none:
diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp
index 160895f23..101834790 100644
--- a/src/passes/FuncCastEmulation.cpp
+++ b/src/passes/FuncCastEmulation.cpp
@@ -67,7 +67,8 @@ static Expression* toABI(Expression* value, Module* module) {
}
case Type::funcref:
case Type::externref:
- case Type::exnref: {
+ case Type::exnref:
+ case Type::anyref: {
WASM_UNREACHABLE("reference types cannot be converted to i64");
}
case Type::none: {
@@ -110,7 +111,8 @@ static Expression* fromABI(Expression* value, Type type, Module* module) {
}
case Type::funcref:
case Type::externref:
- case Type::exnref: {
+ case Type::exnref:
+ case Type::anyref: {
WASM_UNREACHABLE("reference types cannot be converted from i64");
}
case Type::none: {
diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp
index ee288c103..b1ce5f05e 100644
--- a/src/passes/InstrumentLocals.cpp
+++ b/src/passes/InstrumentLocals.cpp
@@ -59,6 +59,7 @@ Name get_f64("get_f64");
Name get_funcref("get_funcref");
Name get_externref("get_externref");
Name get_exnref("get_exnref");
+Name get_anyref("get_anyref");
Name get_v128("get_v128");
Name set_i32("set_i32");
@@ -68,6 +69,7 @@ Name set_f64("set_f64");
Name set_funcref("set_funcref");
Name set_externref("set_externref");
Name set_exnref("set_exnref");
+Name set_anyref("set_anyref");
Name set_v128("set_v128");
struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
@@ -99,6 +101,9 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
case Type::exnref:
import = get_exnref;
break;
+ case Type::anyref:
+ import = get_anyref;
+ break;
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -145,6 +150,9 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
case Type::exnref:
import = set_exnref;
break;
+ case Type::anyref:
+ import = set_anyref;
+ break;
case Type::unreachable:
return; // nothing to do here
case Type::none:
@@ -184,12 +192,18 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> {
set_externref,
{Type::i32, Type::i32, Type::externref},
Type::externref);
- }
- if (curr->features.hasExceptionHandling()) {
- addImport(
- curr, get_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
- addImport(
- curr, set_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
+ if (curr->features.hasExceptionHandling()) {
+ addImport(
+ curr, get_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
+ addImport(
+ curr, set_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref);
+ }
+ if (curr->features.hasAnyref()) {
+ addImport(
+ curr, get_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref);
+ addImport(
+ curr, set_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref);
+ }
}
if (curr->features.hasSIMD()) {
addImport(curr, get_v128, {Type::i32, Type::i32, Type::v128}, Type::v128);
diff --git a/src/shell-interface.h b/src/shell-interface.h
index 92f562b48..ae86d13ec 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -118,6 +118,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
globals[import->name] = {Literal::makeNull(import->type)};
break;
case Type::none:
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index ef7844c60..9768b63c4 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -315,7 +315,20 @@ private:
}
SmallVector<Type, 2> options;
options.push_back(type); // includes itself
- // TODO (GC): subtyping
+ TODO_SINGLE_COMPOUND(type);
+ switch (type.getBasic()) {
+ case Type::anyref:
+ if (wasm.features.hasReferenceTypes()) {
+ options.push_back(Type::funcref);
+ options.push_back(Type::externref);
+ if (wasm.features.hasExceptionHandling()) {
+ options.push_back(Type::exnref);
+ }
+ }
+ break;
+ default:
+ break;
+ }
return pick(options);
}
@@ -1349,6 +1362,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("invalid type");
@@ -1452,6 +1466,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("invalid type");
@@ -1580,6 +1595,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("invalid type");
@@ -1624,6 +1640,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1691,6 +1708,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1717,6 +1735,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1826,6 +1845,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
return makeTrivial(type);
case Type::none:
case Type::unreachable:
@@ -1970,6 +1990,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -2206,6 +2227,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -2412,6 +2434,7 @@ private:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -2592,6 +2615,9 @@ private:
if (wasm.features.hasExceptionHandling()) {
options.push_back(Type::exnref);
}
+ if (wasm.features.hasAnyref()) {
+ options.push_back(Type::anyref);
+ }
return builder.makeRefIsNull(make(pick(options)));
}
@@ -2657,7 +2683,8 @@ private:
.add(FeatureSet::SIMD, Type::v128)
.add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref)
.add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling,
- Type::exnref));
+ Type::exnref)
+ .add(FeatureSet::ReferenceTypes | FeatureSet::Anyref, Type::anyref));
}
Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); }
@@ -2697,7 +2724,7 @@ private:
// - funcref cannot be logged because referenced functions can be inlined or
// removed during optimization
- // - there's no point in logging externref because it is opaque
+ // - there's no point in logging externref or anyref because these are opaque
// - don't bother logging tuples
std::vector<Type> getLoggableTypes() {
return items(
diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h
index c073a994c..200571fd0 100644
--- a/src/tools/spec-wrapper.h
+++ b/src/tools/spec-wrapper.h
@@ -58,6 +58,9 @@ static std::string generateSpecWrapper(Module& wasm) {
case Type::exnref:
ret += "(ref.null exn)";
break;
+ case Type::anyref:
+ ret += "(ref.null any)";
+ break;
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index f04b95304..082e95549 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -87,6 +87,7 @@ struct ToolOptions : public Options {
.addFeature(FeatureSet::TailCall, "tail call operations")
.addFeature(FeatureSet::ReferenceTypes, "reference types")
.addFeature(FeatureSet::Multivalue, "multivalue functions")
+ .addFeature(FeatureSet::Anyref, "anyref type (without GC)")
.add("--no-validation",
"-n",
"Disables validation, assumes inputs are correct",
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp
index 1a7c3544d..7410ff91e 100644
--- a/src/tools/wasm-reduce.cpp
+++ b/src/tools/wasm-reduce.cpp
@@ -598,6 +598,7 @@ struct Reducer
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
continue; // not implemented yet
case Type::none:
case Type::unreachable:
@@ -623,6 +624,7 @@ struct Reducer
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
continue; // not implemented yet
case Type::none:
case Type::unreachable:
@@ -648,6 +650,7 @@ struct Reducer
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
continue; // not implemented yet
case Type::none:
case Type::unreachable:
@@ -673,6 +676,7 @@ struct Reducer
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
continue; // not implemented yet
case Type::none:
case Type::unreachable:
@@ -684,6 +688,7 @@ struct Reducer
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
continue; // not implemented yet
case Type::none:
case Type::unreachable:
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 865a882df..33f78ce7f 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -347,6 +347,8 @@ enum EncodedType {
funcref = -0x10, // 0x70
// opaque host reference type
externref = -0x11, // 0x6f
+ // any reference type
+ anyref = -0x12, // 0x6e
// exception reference type
exnref = -0x18, // 0x68
// func_type form
@@ -358,6 +360,7 @@ enum EncodedType {
enum EncodedHeapType {
func = -0x10, // 0x70
extern_ = -0x11, // 0x6f
+ any = -0x12, // 0x6e
exn = -0x18, // 0x68
};
@@ -380,6 +383,7 @@ extern const char* ExceptionHandlingFeature;
extern const char* TailCallFeature;
extern const char* ReferenceTypesFeature;
extern const char* MultivalueFeature;
+extern const char* AnyrefFeature;
enum Subsection {
NameFunction = 1,
@@ -975,6 +979,9 @@ inline S32LEB binaryType(Type type) {
case Type::exnref:
ret = BinaryConsts::EncodedType::exnref;
break;
+ case Type::anyref:
+ ret = BinaryConsts::EncodedType::anyref;
+ break;
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
}
@@ -994,6 +1001,8 @@ inline S32LEB binaryHeapType(HeapType type) {
ret = BinaryConsts::EncodedHeapType::exn;
break;
case HeapType::AnyKind:
+ ret = BinaryConsts::EncodedHeapType::any;
+ break;
case HeapType::EqKind:
case HeapType::I31Kind:
case HeapType::SignatureKind:
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 1ce3a507c..6c1923482 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -631,6 +631,7 @@ public:
return makeRefNull(value.type);
case Type::externref:
case Type::exnref: // TODO: ExceptionPackage?
+ case Type::anyref:
assert(value.isNull());
return makeRefNull(value.type);
default:
@@ -825,6 +826,7 @@ public:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
return ExpressionManipulator::refNull(curr, curr->type);
case Type::none:
return ExpressionManipulator::nop(curr);
diff --git a/src/wasm-features.h b/src/wasm-features.h
index c35ff0442..5d05b6284 100644
--- a/src/wasm-features.h
+++ b/src/wasm-features.h
@@ -36,7 +36,8 @@ struct FeatureSet {
TailCall = 1 << 7,
ReferenceTypes = 1 << 8,
Multivalue = 1 << 9,
- All = (1 << 10) - 1
+ Anyref = 1 << 10,
+ All = (1 << 11) - 1
};
static std::string toString(Feature f) {
@@ -61,6 +62,8 @@ struct FeatureSet {
return "reference-types";
case Multivalue:
return "multivalue";
+ case Anyref:
+ return "anyref";
default:
WASM_UNREACHABLE("unexpected feature");
}
@@ -84,6 +87,7 @@ struct FeatureSet {
bool hasTailCall() const { return (features & TailCall) != 0; }
bool hasReferenceTypes() const { return (features & ReferenceTypes) != 0; }
bool hasMultivalue() const { return (features & Multivalue) != 0; }
+ bool hasAnyref() const { return (features & Anyref) != 0; }
bool hasAll() const { return (features & All) != 0; }
void makeMVP() { features = MVP; }
@@ -100,6 +104,7 @@ struct FeatureSet {
void setTailCall(bool v = true) { set(TailCall, v); }
void setReferenceTypes(bool v = true) { set(ReferenceTypes, v); }
void setMultivalue(bool v = true) { set(Multivalue, v); }
+ void setAnyref(bool v = true) { set(Anyref, v); }
void setAll(bool v = true) { features = v ? All : MVP; }
void enable(const FeatureSet& other) { features |= other.features; }
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 44cac9d49..361545a2c 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1647,6 +1647,7 @@ public:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1703,6 +1704,7 @@ public:
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 384cc589f..f3973068f 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -50,7 +50,8 @@ public:
funcref,
externref,
exnref,
- _last_basic_id = exnref
+ anyref,
+ _last_basic_id = anyref
};
Type() = default;
@@ -88,11 +89,11 @@ public:
// │ v128 ║ x │ │ x │ x │ V │ ┘
// ├─ Aliases ───╫───┼───┼───┼───┤───────┤
// │ funcref ║ x │ │ x │ x │ f n │ ┐ Ref
- // │ externref ║ x │ │ x │ x │ f? n │ │ f_unc, n_ullable
- // │ anyref ║ x │ │ x │ x │ f? n │ │ ┐
- // │ eqref ║ x │ │ x │ x │ n │ │ │ TODO (GC)
+ // │ externref ║ x │ │ x │ x │ f? n │ │ f_unc
+ // │ exnref ║ x │ │ x │ x │ n │ │ n_ullable
+ // │ anyref ║ x │ │ x │ x │ f? n │ │
+ // │ eqref ║ x │ │ x │ x │ n │ │ ┐ TODO (GC)
// │ i31ref ║ x │ │ x │ x │ │ │ ┘
- // │ exnref ║ x │ │ x │ x │ n │ │
// ├─ Compound ──╫───┼───┼───┼───┤───────┤ │
// │ Ref ║ │ x │ x │ x │ f? n? │◄┘
// │ Tuple ║ │ x │ │ x │ │
@@ -330,11 +331,11 @@ struct HeapType {
enum Kind {
FuncKind,
ExternKind,
+ ExnKind,
AnyKind,
EqKind,
I31Kind,
- ExnKind,
- _last_basic_kind = ExnKind,
+ _last_basic_kind = I31Kind,
SignatureKind,
StructKind,
ArrayKind,
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index ffb98abe4..39a4cea3c 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -69,6 +69,7 @@ Literal::Literal(const Literal& other) : type(other.type) {
case Type::none:
break;
case Type::externref:
+ case Type::anyref:
break; // null
case Type::funcref:
case Type::exnref:
@@ -221,6 +222,7 @@ void Literal::getBits(uint8_t (&buf)[16]) const {
break;
case Type::externref:
case Type::exnref:
+ case Type::anyref:
if (isNull()) {
break;
}
@@ -384,6 +386,10 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
o << "exnref(" << literal.getExceptionPackage() << ")";
}
break;
+ case Type::anyref:
+ assert(literal.isNull() && "TODO: non-null anyref values");
+ o << "anyref(null)";
+ break;
case Type::externref:
assert(literal.isNull() && "TODO: non-null externref values");
o << "externref(null)";
@@ -612,6 +618,7 @@ Literal Literal::eqz() const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -633,6 +640,7 @@ Literal Literal::neg() const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -654,6 +662,7 @@ Literal Literal::abs() const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -758,6 +767,7 @@ Literal Literal::add(const Literal& other) const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -779,6 +789,7 @@ Literal Literal::sub(const Literal& other) const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -896,6 +907,7 @@ Literal Literal::mul(const Literal& other) const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1141,6 +1153,7 @@ Literal Literal::eq(const Literal& other) const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -1162,6 +1175,7 @@ Literal Literal::ne(const Literal& other) const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index b78d6b86b..de82f0656 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -691,6 +691,8 @@ void WasmBinaryWriter::writeFeaturesSection() {
return BinaryConsts::UserSections::ReferenceTypesFeature;
case FeatureSet::Multivalue:
return BinaryConsts::UserSections::MultivalueFeature;
+ case FeatureSet::Anyref:
+ return BinaryConsts::UserSections::AnyrefFeature;
default:
WASM_UNREACHABLE("unexpected feature flag");
}
@@ -1138,6 +1140,8 @@ Type WasmBinaryBuilder::getType() {
return Type::externref;
case BinaryConsts::EncodedType::exnref:
return Type::exnref;
+ case BinaryConsts::EncodedType::anyref:
+ return Type::anyref;
default:
throwError("invalid wasm type: " + std::to_string(type));
}
@@ -1160,6 +1164,8 @@ HeapType WasmBinaryBuilder::getHeapType() {
return HeapType::ExternKind;
case BinaryConsts::EncodedHeapType::exn:
return HeapType::ExnKind;
+ case BinaryConsts::EncodedHeapType::any:
+ return HeapType::AnyKind;
default:
throwError("invalid wasm heap type: " + std::to_string(type));
}
@@ -2203,6 +2209,8 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
wasm.features.setReferenceTypes();
} else if (name == BinaryConsts::UserSections::MultivalueFeature) {
wasm.features.setMultivalue();
+ } else if (name == BinaryConsts::UserSections::AnyrefFeature) {
+ wasm.features.setAnyref();
}
}
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index bac5f958c..e4a33c034 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -874,6 +874,9 @@ Type SExpressionWasmBuilder::stringToType(const char* str,
if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) {
return Type::exnref;
}
+ if (strncmp(str, "anyref", 6) == 0 && (prefix || str[6] == 0)) {
+ return Type::anyref;
+ }
if (allowError) {
return Type::none;
}
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index aee5079c2..64622e814 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -191,6 +191,7 @@ void BinaryInstWriter::visitLoad(Load* curr) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
WASM_UNREACHABLE("unexpected type");
}
@@ -292,6 +293,7 @@ void BinaryInstWriter::visitStore(Store* curr) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
@@ -694,6 +696,7 @@ void BinaryInstWriter::visitConst(Const* curr) {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 729cc88f5..0c49e8dcc 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -256,12 +256,13 @@ std::unordered_map<TypeInfo, uintptr_t> indices = {
{TypeInfo(HeapType(HeapType::FuncKind), true), Type::funcref},
{TypeInfo({Type::externref}), Type::externref},
{TypeInfo(HeapType(HeapType::ExternKind), true), Type::externref},
+ {TypeInfo({Type::exnref}), Type::exnref},
+ {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref},
+ {TypeInfo({Type::anyref}), Type::anyref},
+ {TypeInfo(HeapType(HeapType::AnyKind), true), Type::anyref},
// TODO (GC): Add canonical ids
- // * `(ref null any) == anyref`
// * `(ref null eq) == eqref`
// * `(ref i31) == i31ref`
- {TypeInfo({Type::exnref}), Type::exnref},
- {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref},
};
} // anonymous namespace
@@ -340,7 +341,7 @@ bool Type::isTuple() const {
bool Type::isRef() const {
if (isBasic()) {
- return id >= funcref && id <= exnref;
+ return id >= funcref && id <= anyref;
} else {
return getTypeInfo(*this)->isRef();
}
@@ -366,7 +367,7 @@ bool Type::isException() const {
bool Type::isNullable() const {
if (isBasic()) {
- return id >= funcref && id <= exnref;
+ return id >= funcref && id <= anyref;
} else {
return getTypeInfo(*this)->isNullable();
}
@@ -407,6 +408,7 @@ unsigned Type::getByteSize() const {
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
case Type::unreachable:
break;
@@ -451,6 +453,8 @@ FeatureSet Type::getFeatures() const {
return FeatureSet::ReferenceTypes;
case Type::exnref:
return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling;
+ case Type::anyref:
+ return FeatureSet::ReferenceTypes | FeatureSet::Anyref;
default:
return FeatureSet::MVP;
}
@@ -478,6 +482,8 @@ HeapType Type::getHeapType() const {
return HeapType::ExternKind;
case exnref:
return HeapType::ExnKind;
+ case anyref:
+ return HeapType::AnyKind;
default:
break;
}
@@ -502,10 +508,12 @@ Type Type::get(unsigned byteSize, bool float_) {
}
bool Type::isSubType(Type left, Type right) {
- // TODO (GC): subtyping, currently checks for equality only
if (left == right) {
return true;
}
+ if (left.isRef() && right.isRef()) {
+ return right == Type::anyref;
+ }
if (left.isTuple() && right.isTuple()) {
if (left.size() != right.size()) {
return false;
@@ -533,6 +541,17 @@ Type Type::getLeastUpperBound(Type a, Type b) {
if (a.size() != b.size()) {
return Type::none; // a poison value that must not be consumed
}
+ if (a.isRef()) {
+ if (b.isRef()) {
+ // The LUB of two different reference types is anyref, which may or may
+ // not be a valid type depending on whether the anyref feature is enabled.
+ // When anyref is disabled, it is possible for the finalization of invalid
+ // code to introduce a use of anyref via this function, but that is not a
+ // problem because it will be caught and rejected by validation.
+ return Type::anyref;
+ }
+ return Type::none;
+ }
if (a.isTuple()) {
TypeList types;
types.resize(a.size());
@@ -732,6 +751,9 @@ std::ostream& operator<<(std::ostream& os, Type type) {
case Type::exnref:
os << "exnref";
break;
+ case Type::anyref:
+ os << "anyref";
+ break;
}
} else {
os << *getTypeInfo(type);
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index c6d679a24..80c54abed 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -1363,6 +1363,7 @@ void FunctionValidator::validateMemBytes(uint8_t bytes,
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
WASM_UNREACHABLE("unexpected type");
}
@@ -2176,6 +2177,7 @@ void FunctionValidator::validateAlignment(
case Type::funcref:
case Type::externref:
case Type::exnref:
+ case Type::anyref:
case Type::none:
WASM_UNREACHABLE("invalid type");
}
@@ -2475,6 +2477,20 @@ static void validateModule(Module& module, ValidationInfo& info) {
}
}
+static void validateFeatures(Module& module, ValidationInfo& info) {
+ if (module.features.hasAnyref()) {
+ info.shouldBeTrue(module.features.hasReferenceTypes(),
+ module.features,
+ "--enable-anyref requires --enable-reference-types");
+ }
+ if (module.features.hasExceptionHandling()) { // implies exnref
+ info.shouldBeTrue(
+ module.features.hasReferenceTypes(),
+ module.features,
+ "--enable-exception-handling requires --enable-reference-types");
+ }
+}
+
// TODO: If we want the validator to be part of libwasm rather than libpasses,
// then Using PassRunner::getPassDebug causes a circular dependence. We should
// fix that, perhaps by moving some of the pass infrastructure into libsupport.
@@ -2495,6 +2511,7 @@ bool WasmValidator::validate(Module& module, Flags flags) {
validateTable(module, info);
validateEvents(module, info);
validateModule(module, info);
+ validateFeatures(module, info);
}
// validate additional internal IR details when in pass-debug mode
if (PassRunner::getPassDebug()) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index fe7c1b229..31e05f42e 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -45,6 +45,7 @@ const char* SIMD128Feature = "simd128";
const char* TailCallFeature = "tail-call";
const char* ReferenceTypesFeature = "reference-types";
const char* MultivalueFeature = "multivalue";
+const char* AnyrefFeature = "anyref";
} // namespace UserSections
} // namespace BinaryConsts