summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp9
-rw-r--r--src/binaryen-c.h6
-rw-r--r--src/gen-s-parser.inc644
-rw-r--r--src/ir/ReFinalize.cpp2
-rw-r--r--src/ir/cost.h24
-rw-r--r--src/ir/effects.h2
-rw-r--r--src/ir/gc-type-utils.h13
-rw-r--r--src/ir/linear-execution.h1
-rw-r--r--src/ir/literal-utils.h10
-rw-r--r--src/ir/module-utils.cpp18
-rw-r--r--src/ir/possible-contents.cpp7
-rw-r--r--src/ir/properties.h9
-rw-r--r--src/ir/type-updating.cpp15
-rw-r--r--src/js/binaryen.js-post.js2
-rw-r--r--src/literal.h68
-rw-r--r--src/passes/Heap2Local.cpp7
-rw-r--r--src/passes/InstrumentMemory.cpp2
-rw-r--r--src/passes/OptimizeInstructions.cpp185
-rw-r--r--src/passes/Precompute.cpp5
-rw-r--r--src/passes/Print.cpp93
-rw-r--r--src/passes/StackIR.cpp10
-rw-r--r--src/tools/fuzzing.h11
-rw-r--r--src/tools/fuzzing/fuzzing.cpp31
-rw-r--r--src/tools/fuzzing/heap-types.cpp20
-rw-r--r--src/tools/fuzzing/parameters.h3
-rw-r--r--src/tools/wasm-ctor-eval.cpp1
-rw-r--r--src/tools/wasm-fuzz-types.cpp20
-rw-r--r--src/wasm-binary.h20
-rw-r--r--src/wasm-builder.h98
-rw-r--r--src/wasm-delegations-fields.def18
-rw-r--r--src/wasm-delegations.def2
-rw-r--r--src/wasm-interpreter.h97
-rw-r--r--src/wasm-s-parser.h10
-rw-r--r--src/wasm-type.h43
-rw-r--r--src/wasm.h59
-rw-r--r--src/wasm/literal.cpp74
-rw-r--r--src/wasm/wasm-binary.cpp122
-rw-r--r--src/wasm/wasm-s-parser.cpp127
-rw-r--r--src/wasm/wasm-stack.cpp79
-rw-r--r--src/wasm/wasm-type.cpp149
-rw-r--r--src/wasm/wasm-validator.cpp143
-rw-r--r--src/wasm/wasm.cpp66
-rw-r--r--src/wasm/wat-parser.cpp44
-rw-r--r--src/wasm2js.h8
44 files changed, 432 insertions, 1945 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index f7e8142f1..1dd9fccd2 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1490,8 +1490,6 @@ BinaryenExpressionRef BinaryenI31Get(BinaryenModuleRef module,
// TODO (gc): ref.test
// TODO (gc): ref.cast
// TODO (gc): br_on_cast
-// TODO (gc): rtt.canon
-// TODO (gc): rtt.sub
// TODO (gc): struct.new
// TODO (gc): struct.get
// TODO (gc): struct.set
@@ -4910,13 +4908,6 @@ BinaryenType TypeBuilderGetTempTupleType(TypeBuilderRef builder,
}
return ((TypeBuilder*)builder)->getTempTupleType(Tuple(typeList)).getID();
}
-BinaryenType TypeBuilderGetTempRttType(TypeBuilderRef builder,
- BinaryenIndex depth,
- BinaryenHeapType heapType) {
- return ((TypeBuilder*)builder)
- ->getTempRttType(Rtt(depth, HeapType(heapType)))
- .getID();
-}
BinaryenType TypeBuilderGetTempRefType(TypeBuilderRef builder,
BinaryenHeapType heapType,
int nullable) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 6a2222f71..f02b2cb19 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -943,8 +943,6 @@ BINARYEN_API BinaryenExpressionRef BinaryenI31Get(BinaryenModuleRef module,
// TODO (gc): ref.test
// TODO (gc): ref.cast
// TODO (gc): br_on_cast
-// TODO (gc): rtt.canon
-// TODO (gc): rtt.sub
// TODO (gc): struct.new
// TODO (gc): struct.get
// TODO (gc): struct.set
@@ -2985,10 +2983,6 @@ BINARYEN_API BinaryenType TypeBuilderGetTempTupleType(TypeBuilderRef builder,
BINARYEN_API BinaryenType TypeBuilderGetTempRefType(TypeBuilderRef builder,
BinaryenHeapType heapType,
int nullable);
-// Gets a temporary RTT for use with and owned by the type builder.
-BINARYEN_API BinaryenType TypeBuilderGetTempRttType(TypeBuilderRef builder,
- BinaryenIndex depth,
- BinaryenHeapType heapType);
// Sets the type at `index` to be a subtype of the type at `superIndex`.
BINARYEN_API void TypeBuilderSetSubType(TypeBuilderRef builder,
BinaryenIndex index,
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 301164f87..caf4f5578 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -33,17 +33,9 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 'i': {
- switch (op[10]) {
- case '\0':
- if (strcmp(op, "array.init") == 0) { return makeArrayInit(s); }
- goto parse_error;
- case '_':
- if (strcmp(op, "array.init_static") == 0) { return makeArrayInitStatic(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case 'i':
+ if (strcmp(op, "array.init_static") == 0) { return makeArrayInitStatic(s); }
+ goto parse_error;
case 'l':
if (strcmp(op, "array.len") == 0) { return makeArrayLen(s); }
goto parse_error;
@@ -52,25 +44,9 @@ switch (op[0]) {
case '\0':
if (strcmp(op, "array.new") == 0) { return makeArrayNewStatic(s, false); }
goto parse_error;
- case '_': {
- switch (op[10]) {
- case 'd': {
- switch (op[17]) {
- case '\0':
- if (strcmp(op, "array.new_default") == 0) { return makeArrayNewStatic(s, true); }
- goto parse_error;
- case '_':
- if (strcmp(op, "array.new_default_with_rtt") == 0) { return makeArrayNew(s, true); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'w':
- if (strcmp(op, "array.new_with_rtt") == 0) { return makeArrayNew(s, false); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case '_':
+ if (strcmp(op, "array.new_default") == 0) { return makeArrayNewStatic(s, true); }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -2984,113 +2960,92 @@ switch (op[0]) {
if (strcmp(op, "pop") == 0) { return makePop(s); }
goto parse_error;
case 'r': {
- switch (op[1]) {
- case 'e': {
- switch (op[2]) {
- case 'f': {
- switch (op[4]) {
- case 'a': {
- switch (op[7]) {
- case 'd':
- if (strcmp(op, "ref.as_data") == 0) { return makeRefAs(s, RefAsData); }
- goto parse_error;
- case 'f':
- if (strcmp(op, "ref.as_func") == 0) { return makeRefAs(s, RefAsFunc); }
- goto parse_error;
- case 'i':
- if (strcmp(op, "ref.as_i31") == 0) { return makeRefAs(s, RefAsI31); }
- goto parse_error;
- case 'n':
- if (strcmp(op, "ref.as_non_null") == 0) { return makeRefAs(s, RefAsNonNull); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'c': {
- switch (op[8]) {
- case '\0':
- if (strcmp(op, "ref.cast") == 0) { return makeRefCast(s); }
- goto parse_error;
- case '_': {
- switch (op[9]) {
- case 'n':
- if (strcmp(op, "ref.cast_nop_static") == 0) { return makeRefCastNopStatic(s); }
- goto parse_error;
- case 's':
- if (strcmp(op, "ref.cast_static") == 0) { return makeRefCastStatic(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
- }
- }
- case 'e':
- if (strcmp(op, "ref.eq") == 0) { return makeRefEq(s); }
+ switch (op[2]) {
+ case 'f': {
+ switch (op[4]) {
+ case 'a': {
+ switch (op[7]) {
+ case 'd':
+ if (strcmp(op, "ref.as_data") == 0) { return makeRefAs(s, RefAsData); }
goto parse_error;
case 'f':
- if (strcmp(op, "ref.func") == 0) { return makeRefFunc(s); }
+ if (strcmp(op, "ref.as_func") == 0) { return makeRefAs(s, RefAsFunc); }
+ goto parse_error;
+ case 'i':
+ if (strcmp(op, "ref.as_i31") == 0) { return makeRefAs(s, RefAsI31); }
goto parse_error;
- case 'i': {
- switch (op[7]) {
- case 'd':
- if (strcmp(op, "ref.is_data") == 0) { return makeRefIs(s, RefIsData); }
- goto parse_error;
- case 'f':
- if (strcmp(op, "ref.is_func") == 0) { return makeRefIs(s, RefIsFunc); }
- goto parse_error;
- case 'i':
- if (strcmp(op, "ref.is_i31") == 0) { return makeRefIs(s, RefIsI31); }
- goto parse_error;
- case 'n':
- if (strcmp(op, "ref.is_null") == 0) { return makeRefIs(s, RefIsNull); }
- goto parse_error;
- default: goto parse_error;
- }
- }
case 'n':
- if (strcmp(op, "ref.null") == 0) { return makeRefNull(s); }
+ if (strcmp(op, "ref.as_non_null") == 0) { return makeRefAs(s, RefAsNonNull); }
goto parse_error;
- case 't': {
- switch (op[8]) {
- case '\0':
- if (strcmp(op, "ref.test") == 0) { return makeRefTest(s); }
- goto parse_error;
- case '_':
- if (strcmp(op, "ref.test_static") == 0) { return makeRefTestStatic(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
- case 't': {
- switch (op[3]) {
- case 'h':
- if (strcmp(op, "rethrow") == 0) { return makeRethrow(s); }
+ case 'c': {
+ switch (op[9]) {
+ case 'n':
+ if (strcmp(op, "ref.cast_nop_static") == 0) { return makeRefCastNopStatic(s); }
goto parse_error;
- case 'u': {
- switch (op[6]) {
+ case 's':
+ if (strcmp(op, "ref.cast_static") == 0) { return makeRefCastStatic(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'e':
+ if (strcmp(op, "ref.eq") == 0) { return makeRefEq(s); }
+ goto parse_error;
+ case 'f':
+ if (strcmp(op, "ref.func") == 0) { return makeRefFunc(s); }
+ goto parse_error;
+ case 'i': {
+ switch (op[7]) {
+ case 'd':
+ if (strcmp(op, "ref.is_data") == 0) { return makeRefIs(s, RefIsData); }
+ goto parse_error;
+ case 'f':
+ if (strcmp(op, "ref.is_func") == 0) { return makeRefIs(s, RefIsFunc); }
+ goto parse_error;
+ case 'i':
+ if (strcmp(op, "ref.is_i31") == 0) { return makeRefIs(s, RefIsI31); }
+ goto parse_error;
+ case 'n':
+ if (strcmp(op, "ref.is_null") == 0) { return makeRefIs(s, RefIsNull); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'n':
+ if (strcmp(op, "ref.null") == 0) { return makeRefNull(s); }
+ goto parse_error;
+ case 't':
+ if (strcmp(op, "ref.test_static") == 0) { return makeRefTestStatic(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 't': {
+ switch (op[3]) {
+ case 'h':
+ if (strcmp(op, "rethrow") == 0) { return makeRethrow(s); }
+ goto parse_error;
+ case 'u': {
+ switch (op[6]) {
+ case '\0':
+ if (strcmp(op, "return") == 0) { return makeReturn(s); }
+ goto parse_error;
+ case '_': {
+ switch (op[11]) {
case '\0':
- if (strcmp(op, "return") == 0) { return makeReturn(s); }
+ if (strcmp(op, "return_call") == 0) { return makeCall(s, /*isReturn=*/true); }
goto parse_error;
case '_': {
- switch (op[11]) {
- case '\0':
- if (strcmp(op, "return_call") == 0) { return makeCall(s, /*isReturn=*/true); }
+ switch (op[12]) {
+ case 'i':
+ if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
+ goto parse_error;
+ case 'r':
+ if (strcmp(op, "return_call_ref") == 0) { return makeCallRef(s, /*isReturn=*/true); }
goto parse_error;
- case '_': {
- switch (op[12]) {
- case 'i':
- if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
- goto parse_error;
- case 'r':
- if (strcmp(op, "return_call_ref") == 0) { return makeCallRef(s, /*isReturn=*/true); }
- goto parse_error;
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
@@ -3103,20 +3058,6 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 't': {
- switch (op[4]) {
- case 'c':
- if (strcmp(op, "rtt.canon") == 0) { return makeRttCanon(s); }
- goto parse_error;
- case 'f':
- if (strcmp(op, "rtt.fresh_sub") == 0) { return makeRttFreshSub(s); }
- goto parse_error;
- case 's':
- if (strcmp(op, "rtt.sub") == 0) { return makeRttSub(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
@@ -3321,25 +3262,9 @@ switch (op[0]) {
case '\0':
if (strcmp(op, "struct.new") == 0) { return makeStructNewStatic(s, false); }
goto parse_error;
- case '_': {
- switch (op[11]) {
- case 'd': {
- switch (op[18]) {
- case '\0':
- if (strcmp(op, "struct.new_default") == 0) { return makeStructNewStatic(s, true); }
- goto parse_error;
- case '_':
- if (strcmp(op, "struct.new_default_with_rtt") == 0) { return makeStructNew(s, true); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'w':
- if (strcmp(op, "struct.new_with_rtt") == 0) { return makeStructNew(s, false); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case '_':
+ if (strcmp(op, "struct.new_default") == 0) { return makeStructNewStatic(s, true); }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -3631,25 +3556,13 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 'i': {
- switch (op[10]) {
- case '\0':
- if (op == "array.init"sv) {
- auto ret = makeArrayInit(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "array.init_static"sv) {
- auto ret = makeArrayInitStatic(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'i':
+ if (op == "array.init_static"sv) {
+ auto ret = makeArrayInitStatic(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
case 'l':
if (op == "array.len"sv) {
auto ret = makeArrayLen(ctx, in);
@@ -3666,37 +3579,13 @@ switch (op[0]) {
return *ret;
}
goto parse_error;
- case '_': {
- switch (op[10]) {
- case 'd': {
- switch (op[17]) {
- case '\0':
- if (op == "array.new_default"sv) {
- auto ret = makeArrayNewStatic(ctx, in, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "array.new_default_with_rtt"sv) {
- auto ret = makeArrayNew(ctx, in, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'w':
- if (op == "array.new_with_rtt"sv) {
- auto ret = makeArrayNew(ctx, in, false);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case '_':
+ if (op == "array.new_default"sv) {
+ auto ret = makeArrayNewStatic(ctx, in, true);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -8594,197 +8483,168 @@ switch (op[0]) {
}
goto parse_error;
case 'r': {
- switch (op[1]) {
- case 'e': {
- switch (op[2]) {
- case 'f': {
- switch (op[4]) {
- case 'a': {
- switch (op[7]) {
- case 'd':
- if (op == "ref.as_data"sv) {
- auto ret = makeRefAs(ctx, in, RefAsData);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'f':
- if (op == "ref.as_func"sv) {
- auto ret = makeRefAs(ctx, in, RefAsFunc);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "ref.as_i31"sv) {
- auto ret = makeRefAs(ctx, in, RefAsI31);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'n':
- if (op == "ref.as_non_null"sv) {
- auto ret = makeRefAs(ctx, in, RefAsNonNull);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ switch (op[2]) {
+ case 'f': {
+ switch (op[4]) {
+ case 'a': {
+ switch (op[7]) {
+ case 'd':
+ if (op == "ref.as_data"sv) {
+ auto ret = makeRefAs(ctx, in, RefAsData);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
- case 'c': {
- switch (op[8]) {
- case '\0':
- if (op == "ref.cast"sv) {
- auto ret = makeRefCast(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_': {
- switch (op[9]) {
- case 'n':
- if (op == "ref.cast_nop_static"sv) {
- auto ret = makeRefCastNopStatic(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 's':
- if (op == "ref.cast_static"sv) {
- auto ret = makeRefCastStatic(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
+ goto parse_error;
+ case 'f':
+ if (op == "ref.as_func"sv) {
+ auto ret = makeRefAs(ctx, in, RefAsFunc);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
- case 'e':
- if (op == "ref.eq"sv) {
- auto ret = makeRefEq(ctx, in);
+ goto parse_error;
+ case 'i':
+ if (op == "ref.as_i31"sv) {
+ auto ret = makeRefAs(ctx, in, RefAsI31);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'n':
+ if (op == "ref.as_non_null"sv) {
+ auto ret = makeRefAs(ctx, in, RefAsNonNull);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'c': {
+ switch (op[9]) {
+ case 'n':
+ if (op == "ref.cast_nop_static"sv) {
+ auto ret = makeRefCastNopStatic(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 's':
+ if (op == "ref.cast_static"sv) {
+ auto ret = makeRefCastStatic(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'e':
+ if (op == "ref.eq"sv) {
+ auto ret = makeRefEq(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'f':
+ if (op == "ref.func"sv) {
+ auto ret = makeRefFunc(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'i': {
+ switch (op[7]) {
+ case 'd':
+ if (op == "ref.is_data"sv) {
+ auto ret = makeRefIs(ctx, in, RefIsData);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case 'f':
- if (op == "ref.func"sv) {
- auto ret = makeRefFunc(ctx, in);
+ if (op == "ref.is_func"sv) {
+ auto ret = makeRefIs(ctx, in, RefIsFunc);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case 'i': {
- switch (op[7]) {
- case 'd':
- if (op == "ref.is_data"sv) {
- auto ret = makeRefIs(ctx, in, RefIsData);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'f':
- if (op == "ref.is_func"sv) {
- auto ret = makeRefIs(ctx, in, RefIsFunc);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "ref.is_i31"sv) {
- auto ret = makeRefIs(ctx, in, RefIsI31);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'n':
- if (op == "ref.is_null"sv) {
- auto ret = makeRefIs(ctx, in, RefIsNull);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'i':
+ if (op == "ref.is_i31"sv) {
+ auto ret = makeRefIs(ctx, in, RefIsI31);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
case 'n':
- if (op == "ref.null"sv) {
- auto ret = makeRefNull(ctx, in);
+ if (op == "ref.is_null"sv) {
+ auto ret = makeRefIs(ctx, in, RefIsNull);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case 't': {
- switch (op[8]) {
- case '\0':
- if (op == "ref.test"sv) {
- auto ret = makeRefTest(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "ref.test_static"sv) {
- auto ret = makeRefTestStatic(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
- case 't': {
- switch (op[3]) {
- case 'h':
- if (op == "rethrow"sv) {
- auto ret = makeRethrow(ctx, in);
+ case 'n':
+ if (op == "ref.null"sv) {
+ auto ret = makeRefNull(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 't':
+ if (op == "ref.test_static"sv) {
+ auto ret = makeRefTestStatic(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 't': {
+ switch (op[3]) {
+ case 'h':
+ if (op == "rethrow"sv) {
+ auto ret = makeRethrow(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'u': {
+ switch (op[6]) {
+ case '\0':
+ if (op == "return"sv) {
+ auto ret = makeReturn(ctx, in);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case 'u': {
- switch (op[6]) {
+ case '_': {
+ switch (op[11]) {
case '\0':
- if (op == "return"sv) {
- auto ret = makeReturn(ctx, in);
+ if (op == "return_call"sv) {
+ auto ret = makeCall(ctx, in, /*isReturn=*/true);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case '_': {
- switch (op[11]) {
- case '\0':
- if (op == "return_call"sv) {
- auto ret = makeCall(ctx, in, /*isReturn=*/true);
+ switch (op[12]) {
+ case 'i':
+ if (op == "return_call_indirect"sv) {
+ auto ret = makeCallIndirect(ctx, in, /*isReturn=*/true);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case '_': {
- switch (op[12]) {
- case 'i':
- if (op == "return_call_indirect"sv) {
- auto ret = makeCallIndirect(ctx, in, /*isReturn=*/true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'r':
- if (op == "return_call_ref"sv) {
- auto ret = makeCallRef(ctx, in, /*isReturn=*/true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'r':
+ if (op == "return_call_ref"sv) {
+ auto ret = makeCallRef(ctx, in, /*isReturn=*/true);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -8797,32 +8657,6 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 't': {
- switch (op[4]) {
- case 'c':
- if (op == "rtt.canon"sv) {
- auto ret = makeRttCanon(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'f':
- if (op == "rtt.fresh_sub"sv) {
- auto ret = makeRttFreshSub(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 's':
- if (op == "rtt.sub"sv) {
- auto ret = makeRttSub(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
@@ -9151,37 +8985,13 @@ switch (op[0]) {
return *ret;
}
goto parse_error;
- case '_': {
- switch (op[11]) {
- case 'd': {
- switch (op[18]) {
- case '\0':
- if (op == "struct.new_default"sv) {
- auto ret = makeStructNewStatic(ctx, in, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "struct.new_default_with_rtt"sv) {
- auto ret = makeStructNew(ctx, in, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'w':
- if (op == "struct.new_with_rtt"sv) {
- auto ret = makeStructNew(ctx, in, false);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case '_':
+ if (op == "struct.new_default"sv) {
+ auto ret = makeStructNewStatic(ctx, in, true);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
default: goto parse_error;
}
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 771553e11..3a5e4172d 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -160,8 +160,6 @@ void ReFinalize::visitBrOn(BrOn* curr) {
updateBreakValueType(curr->name, curr->getSentType());
}
}
-void ReFinalize::visitRttCanon(RttCanon* curr) { curr->finalize(); }
-void ReFinalize::visitRttSub(RttSub* curr) { curr->finalize(); }
void ReFinalize::visitStructNew(StructNew* curr) { curr->finalize(); }
void ReFinalize::visitStructGet(StructGet* curr) { curr->finalize(); }
void ReFinalize::visitStructSet(StructSet* curr) { curr->finalize(); }
diff --git a/src/ir/cost.h b/src/ir/cost.h
index b48b777e1..823e58ded 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -604,35 +604,24 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
// Casts have a very high cost because in the VM they end up implemented as
// a combination of loads and branches. Given they contain branches, we do
// not want to add any more such work.
- return Unacceptable + nullCheckCost(curr->ref) + visit(curr->ref) +
- maybeVisit(curr->rtt);
+ return Unacceptable + nullCheckCost(curr->ref) + visit(curr->ref);
}
CostType visitRefCast(RefCast* curr) {
- return Unacceptable + nullCheckCost(curr->ref) + visit(curr->ref) +
- maybeVisit(curr->rtt);
+ return Unacceptable + nullCheckCost(curr->ref) + visit(curr->ref);
}
CostType visitBrOn(BrOn* curr) {
// BrOn of a null can be fairly fast, but anything else is a cast check
// basically, and an unacceptable cost.
CostType base =
curr->op == BrOnNull || curr->op == BrOnNonNull ? 2 : Unacceptable;
- return base + nullCheckCost(curr->ref) + maybeVisit(curr->ref) +
- maybeVisit(curr->rtt);
- }
- CostType visitRttCanon(RttCanon* curr) {
- // TODO: investigate actual RTT costs in VMs
- return 1;
- }
- CostType visitRttSub(RttSub* curr) {
- // TODO: investigate actual RTT costs in VMs
- return 2 + visit(curr->parent);
+ return base + nullCheckCost(curr->ref) + maybeVisit(curr->ref);
}
CostType visitStructNew(StructNew* curr) {
// While allocation itself is almost free with generational GC, there is
// at least some baseline cost, plus writing the fields. (If we use default
// values for the fields, then it is possible they are all 0 and if so, we
// can get that almost for free as well, so don't add anything there.)
- CostType ret = 4 + maybeVisit(curr->rtt) + curr->operands.size();
+ CostType ret = 4 + curr->operands.size();
for (auto* child : curr->operands) {
ret += visit(child);
}
@@ -645,11 +634,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->value);
}
CostType visitArrayNew(ArrayNew* curr) {
- return 4 + maybeVisit(curr->rtt) + visit(curr->size) +
- maybeVisit(curr->init);
+ return 4 + visit(curr->size) + maybeVisit(curr->init);
}
CostType visitArrayInit(ArrayInit* curr) {
- CostType ret = 4 + maybeVisit(curr->rtt);
+ CostType ret = 4;
for (auto* child : curr->values) {
ret += visit(child);
}
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 8d643ffe3..5e50441ac 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -678,8 +678,6 @@ private:
parent.implicitTrap = true;
}
void visitBrOn(BrOn* curr) { parent.breakTargets.insert(curr->name); }
- void visitRttCanon(RttCanon* curr) {}
- void visitRttSub(RttSub* curr) {}
void visitStructNew(StructNew* curr) {}
void visitStructGet(StructGet* curr) {
if (curr->ref->type == Type::unreachable) {
diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h
index 584cde83c..cec4490e2 100644
--- a/src/ir/gc-type-utils.h
+++ b/src/ir/gc-type-utils.h
@@ -56,14 +56,11 @@ inline EvaluationResult evaluateKindCheck(Expression* curr) {
flip = true;
[[fallthrough]];
case BrOnCast:
- if (!br->rtt) {
- // This is a static cast check, which we may be able to resolve at
- // compile time. Note that the type must be non-nullable for us to
- // succeed at that inference, as otherwise a null can make us fail.
- if (Type::isSubType(br->ref->type,
- Type(br->intendedType, NonNullable))) {
- return flip ? Failure : Success;
- }
+ // Note that the type must be non-nullable for us to succeed since a
+ // null would make us fail.
+ if (Type::isSubType(br->ref->type,
+ Type(br->intendedType, NonNullable))) {
+ return flip ? Failure : Success;
}
return Unknown;
case BrOnNonFunc:
diff --git a/src/ir/linear-execution.h b/src/ir/linear-execution.h
index 230bafee5..99b3a2a22 100644
--- a/src/ir/linear-execution.h
+++ b/src/ir/linear-execution.h
@@ -130,7 +130,6 @@ struct LinearExecutionWalker : public PostWalker<SubType, VisitorType> {
case Expression::Id::BrOnId: {
self->pushTask(SubType::doVisitBrOn, currp);
self->pushTask(SubType::doNoteNonLinear, currp);
- self->maybePushTask(SubType::scan, &curr->cast<BrOn>()->rtt);
self->pushTask(SubType::scan, &curr->cast<BrOn>()->ref);
break;
}
diff --git a/src/ir/literal-utils.h b/src/ir/literal-utils.h
index ad022344e..0131ecdc9 100644
--- a/src/ir/literal-utils.h
+++ b/src/ir/literal-utils.h
@@ -33,17 +33,9 @@ inline bool canMakeZero(Type type) {
if (type.isNonNullable()) {
return false;
}
- if (type.isRtt() && type.getRtt().hasDepth()) {
- // An rtt with depth cannot be constructed as a simple zero: we'd need to
- // create not just a zero (an rtt.canon) but also some rtt.subs that add to
- // the depth, so disallow that. Also, there is no practical way to create a
- // zero Literal for such a type, as we'd need to supply the list of super
- // types somehow, and creating a zero Literal is how makeZero works.
- return false;
- }
if (type.isTuple()) {
for (auto t : type) {
- if (!canMakeZero(t)) {
+ if (t.isNonNullable()) {
return false;
}
}
diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp
index 38bb6f3d9..33f8ac926 100644
--- a/src/ir/module-utils.cpp
+++ b/src/ir/module-utils.cpp
@@ -55,8 +55,6 @@ struct CodeScanner
counts.note(call->heapType);
} else if (curr->is<RefNull>()) {
counts.note(curr->type);
- } else if (curr->is<RttCanon>() || curr->is<RttSub>()) {
- counts.note(curr->type.getRtt().heapType);
} else if (auto* make = curr->dynCast<StructNew>()) {
handleMake(make);
} else if (auto* make = curr->dynCast<ArrayNew>()) {
@@ -64,12 +62,12 @@ struct CodeScanner
} else if (auto* make = curr->dynCast<ArrayInit>()) {
handleMake(make);
} else if (auto* cast = curr->dynCast<RefCast>()) {
- handleCast(cast);
+ counts.note(cast->intendedType);
} else if (auto* cast = curr->dynCast<RefTest>()) {
- handleCast(cast);
+ counts.note(cast->intendedType);
} else if (auto* cast = curr->dynCast<BrOn>()) {
if (cast->op == BrOnCast || cast->op == BrOnCastFail) {
- handleCast(cast);
+ counts.note(cast->intendedType);
}
} else if (auto* get = curr->dynCast<StructGet>()) {
counts.note(get->ref->type);
@@ -86,18 +84,10 @@ struct CodeScanner
}
template<typename T> void handleMake(T* curr) {
- if (!curr->rtt && curr->type != Type::unreachable) {
+ if (curr->type != Type::unreachable) {
counts.note(curr->type.getHeapType());
}
}
-
- template<typename T> void handleCast(T* curr) {
- // Some operations emit a HeapType in the binary format, if they are
- // static and not dynamic (if dynamic, the RTT provides the heap type).
- if (!curr->rtt) {
- counts.note(curr->intendedType);
- }
- }
};
Counts getHeapTypeCounts(Module& wasm) {
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index ab0d379f6..48a632576 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -416,8 +416,6 @@ struct InfoCollector
handleBreakValue(curr);
receiveChildValue(curr->ref, curr);
}
- void visitRttCanon(RttCanon* curr) { addRoot(curr); }
- void visitRttSub(RttSub* curr) { addRoot(curr); }
void visitRefAs(RefAs* curr) {
// TODO: optimize when possible: like RefCast, not all values flow through.
receiveChildValue(curr->value, curr);
@@ -1677,9 +1675,8 @@ void Flower::flowRefCast(const PossibleContents& contents, RefCast* cast) {
// emitting a Many in any of these code paths
filtered = contents;
} else {
- auto intendedType = cast->getIntendedType();
bool isSubType =
- HeapType::isSubType(contents.getType().getHeapType(), intendedType);
+ HeapType::isSubType(contents.getType().getHeapType(), cast->intendedType);
if (isSubType) {
// The contents are not Many, but their heap type is a subtype of the
// intended type, so we'll pass that through. Note that we pass the entire
@@ -1694,7 +1691,7 @@ void Flower::flowRefCast(const PossibleContents& contents, RefCast* cast) {
if (mayBeNull) {
// A null is possible, so pass that along.
filtered.combine(
- PossibleContents::literal(Literal::makeNull(intendedType)));
+ PossibleContents::literal(Literal::makeNull(cast->intendedType)));
}
}
if (!filtered.isNone()) {
diff --git a/src/ir/properties.h b/src/ir/properties.h
index 204b33e1e..4bd66b1d5 100644
--- a/src/ir/properties.h
+++ b/src/ir/properties.h
@@ -75,8 +75,8 @@ inline bool isNamedControlFlow(Expression* curr) {
// at compile time, and passes that propagate constants can try to propagate it.
// Constant expressions are also allowed in global initializers in wasm. Also
// when two constant expressions compare equal at compile time, their values at
-// runtime will be equal as well.
-// TODO: look into adding more things here like RttCanon.
+// runtime will be equal as well. TODO: combine this with
+// isValidInConstantExpression or find better names(#4845)
inline bool isSingleConstantExpression(const Expression* curr) {
return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>();
}
@@ -407,9 +407,8 @@ bool isGenerative(Expression* curr, FeatureSet features);
inline bool isValidInConstantExpression(Expression* expr, FeatureSet features) {
if (isSingleConstantExpression(expr) || expr->is<GlobalGet>() ||
- expr->is<RttCanon>() || expr->is<RttSub>() || expr->is<StructNew>() ||
- expr->is<ArrayNew>() || expr->is<ArrayInit>() || expr->is<I31New>() ||
- expr->is<StringConst>()) {
+ expr->is<StructNew>() || expr->is<ArrayNew>() || expr->is<ArrayInit>() ||
+ expr->is<I31New>() || expr->is<StringConst>()) {
return true;
}
diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp
index b08cca295..5452613bb 100644
--- a/src/ir/type-updating.cpp
+++ b/src/ir/type-updating.cpp
@@ -117,9 +117,6 @@ void GlobalTypeRewriter::update() {
if (type.isRef()) {
return Type(getNew(type.getHeapType()), type.getNullability());
}
- if (type.isRtt()) {
- return Type(Rtt(type.getRtt().depth, getNew(type.getHeapType())));
- }
if (type.isTuple()) {
auto tuple = type.getTuple();
for (auto& t : tuple.types) {
@@ -251,18 +248,6 @@ Type GlobalTypeRewriter::getTempType(Type type) {
typeBuilder.getTempHeapType(indexedTypes.indices[heapType]),
type.getNullability());
}
- if (type.isRtt()) {
- auto rtt = type.getRtt();
- auto newRtt = rtt;
- auto heapType = type.getHeapType();
- if (!indexedTypes.indices.count(heapType)) {
- // See above with references.
- return type;
- }
- newRtt.heapType =
- typeBuilder.getTempHeapType(indexedTypes.indices[heapType]);
- return typeBuilder.getTempRttType(newRtt);
- }
if (type.isTuple()) {
auto& tuple = type.getTuple();
auto newTuple = tuple;
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index d2a8eb7f5..6ba5454e9 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -111,8 +111,6 @@ function initializeConstants() {
'RefTest',
'RefCast',
'BrOn',
- 'RttCanon',
- 'RttSub',
'StructNew',
'StructGet',
'StructSet',
diff --git a/src/literal.h b/src/literal.h
index 6696103e3..ffd565c71 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -32,7 +32,6 @@ namespace wasm {
class Literals;
struct GCData;
-struct RttSupers;
class Literal {
// store only integers, whose bits are deterministic. floats
@@ -51,21 +50,6 @@ class Literal {
// Array, and for a Struct, is just the fields in order). The type is used
// to indicate whether this is a Struct or an Array, and of what type.
std::shared_ptr<GCData> gcData;
- // RTT values are "structural" in that the MVP doc says that multiple
- // invocations of ref.canon return things that are observably identical, and
- // the same is true for ref.sub. That is, what matters is the types; there
- // is no unique identifier created in each ref.canon/sub. To track the
- // types, we maintain a simple vector of the supertypes. Thus, an rtt.canon
- // of type A will have an empty vector; an rtt.sub of type B of that initial
- // canon would have a vector of size 1 containing A; a subsequent rtt.sub
- // would have A, B, and so forth.
- // (This encoding is very inefficient and not at all what a production VM
- // would do, but it is simple.)
- // The unique_ptr here is to avoid increasing the size of the union as well
- // as the Literal class itself.
- // To support the experimental RttFreshSub instruction, we not only store
- // the type, but also a reference to an allocation.
- std::unique_ptr<RttSupers> rttSupers;
// TODO: Literals of type `anyref` can only be `null` currently but we
// will need to represent external values eventually, to
// 1) run the spec tests and fuzzer with reference types enabled and
@@ -97,7 +81,6 @@ public:
explicit Literal(Name func, HeapType type)
: func(func), type(type, NonNullable) {}
explicit Literal(std::shared_ptr<GCData> gcData, HeapType type);
- explicit Literal(std::unique_ptr<RttSupers>&& rttSupers, Type type);
Literal(const Literal& other);
Literal& operator=(const Literal& other);
~Literal();
@@ -267,10 +250,6 @@ public:
return lit;
}
- // Get the canonical RTT value for a given HeapType. For nominal types, the
- // canonical RTT reflects the static supertype chain.
- static Literal makeCanonicalRtt(HeapType type);
-
Literal castToF32();
Literal castToF64();
Literal castToI32();
@@ -303,7 +282,6 @@ public:
return func;
}
std::shared_ptr<GCData> getGCData() const;
- const RttSupers& getRttSupers() const;
// careful!
int32_t* geti32Ptr() {
@@ -666,11 +644,6 @@ public:
Literal relaxedFmaF64x2(const Literal& left, const Literal& right) const;
Literal relaxedFmsF64x2(const Literal& left, const Literal& right) const;
- // Checks if an RTT value is a sub-rtt of another, that is, whether GC data
- // with this object's RTT can be successfuly cast using the other RTT
- // according to the wasm rules for that.
- bool isSubRtt(const Literal& other) const;
-
private:
Literal addSatSI8(const Literal& other) const;
Literal addSatUI8(const Literal& other) const;
@@ -721,41 +694,18 @@ public:
std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
-// A GC Struct or Array is a set of values with a run-time type saying what it
-// is. In the case of static (rtt-free) typing, the rtt is not present and
-// instead we have a static type.
+// A GC Struct or Array is a set of values with a type saying how it should be
+// interpreted.
struct GCData {
- // The runtime type info for this struct or array.
- Literal rtt;
+ // The type of this struct or array.
+ HeapType type;
// The element or field values.
Literals values;
- GCData(Literal rtt, Literals values) : rtt(rtt), values(values) {}
-};
-
-struct RttSuper {
- // The type of the super.
- HeapType type;
- // A shared allocation, used to implement rtt.fresh_sub. This is null for a
- // normal sub, and for a fresh one we allocate a value here, which can then be
- // used to differentiate rtts. (The allocation is shared so that when copying
- // an rtt we remain equal.)
- // TODO: Remove or optimize this when the spec stabilizes.
- std::shared_ptr<size_t> freshPtr;
-
- RttSuper(HeapType type) : type(type) {}
-
- void makeFresh() { freshPtr = std::make_shared<size_t>(); }
-
- bool operator==(const RttSuper& other) const {
- return type == other.type && freshPtr == other.freshPtr;
- }
- bool operator!=(const RttSuper& other) const { return !(*this == other); }
+ GCData(HeapType type, Literals values) : type(type), values(values) {}
};
-struct RttSupers : std::vector<RttSuper> {};
-
} // namespace wasm
namespace std {
@@ -801,14 +751,6 @@ template<> struct hash<wasm::Literal> {
// other non-null reference type literals cannot represent concrete
// values, i.e. there is no concrete anyref or eqref other than null.
WASM_UNREACHABLE("unexpected type");
- } else if (a.type.isRtt()) {
- const auto& supers = a.getRttSupers();
- wasm::rehash(digest, supers.size());
- for (auto super : supers) {
- wasm::rehash(digest, super.type.getID());
- wasm::rehash(digest, uintptr_t(super.freshPtr.get()));
- }
- return digest;
}
WASM_UNREACHABLE("unexpected type");
}
diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp
index 19259e864..86235b001 100644
--- a/src/passes/Heap2Local.cpp
+++ b/src/passes/Heap2Local.cpp
@@ -43,9 +43,8 @@
//
// ;; Allocate a boxed integer of 42 and save the reference to it.
// (local.set $ref
-// (struct.new_with_rtt $boxed-int
+// (struct.new $boxed-int
// (i32.const 42)
-// (rtt.canon $boxed-int)
// )
// )
//
@@ -407,10 +406,6 @@ struct Heap2LocalOptimizer {
}
}
- // Drop the RTT (as it may have side effects; leave it to other passes).
- if (allocation->rtt) {
- contents.push_back(builder.makeDrop(allocation->rtt));
- }
// Replace the allocation with a null reference. This changes the type
// from non-nullable to nullable, but as we optimize away the code that
// the allocation reaches, we will handle that.
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index 073c78822..1180c5183 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -54,7 +54,7 @@
//
// GC struct and array operations are similarly instrumented, but without their
// pointers (which are references), and we only log MVP wasm types (i.e., not
-// references or rtts).
+// references).
//
#include "asmjs/shared-constants.h"
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 55176a6e9..828b2fdc9 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1434,10 +1434,9 @@ struct OptimizeInstructions
// is, if casts of the type do not affect our behavior (which is the case in
// ref.eq for example).
//
- // |requiredType| is the type we require as the final output here, or a
- // subtype of it. We will not remove a cast that would leave something that
- // would break that. If |requiredType| is not provided we will accept any type
- // there.
+ // |requiredType| is the required supertype of the final output. We will not
+ // remove a cast that would leave something that would break that. If
+ // |requiredType| is not provided we will accept any type there.
//
// See "notes on removing casts", above, for when this is safe to do.
void skipCast(Expression*& input,
@@ -1453,7 +1452,7 @@ struct OptimizeInstructions
continue;
}
} else if (auto* cast = input->dynCast<RefCast>()) {
- if (!cast->rtt && Type::isSubType(cast->ref->type, requiredType)) {
+ if (Type::isSubType(cast->ref->type, requiredType)) {
input = cast->ref;
continue;
}
@@ -1705,7 +1704,7 @@ struct OptimizeInstructions
auto fallthrough =
Properties::getFallthrough(curr->ref, getPassOptions(), *getModule());
- auto intendedType = curr->getIntendedType();
+ auto intendedType = curr->intendedType;
// If the value is a null, it will just flow through, and we do not need
// the cast. However, if that would change the type, then things are less
@@ -1716,13 +1715,8 @@ struct OptimizeInstructions
// Replace the expression with drops of the inputs, and a null. Note
// that we provide a null of the previous type, so that we do not alter
// the type received by our parent.
- std::vector<Expression*> items;
- items.push_back(builder.makeDrop(curr->ref));
- if (curr->rtt) {
- items.push_back(builder.makeDrop(curr->rtt));
- }
- items.push_back(builder.makeRefNull(intendedType));
- Expression* rep = builder.makeBlock(items);
+ Expression* rep = builder.makeSequence(builder.makeDrop(curr->ref),
+ builder.makeRefNull(intendedType));
if (curr->ref->type.isNonNullable()) {
// Avoid a type change by forcing to be non-nullable. In practice,
// this would have trapped before we get here, so this is just for
@@ -1737,22 +1731,17 @@ struct OptimizeInstructions
}
// For the cast to be able to succeed, the value being cast must be a
- // subtype of the desired type, as RTT subtyping is a subset of static
- // subtyping. For example, trying to cast an array to a struct would be
- // incompatible.
+ // subtype of the desired type. For example, trying to cast an array to a
+ // struct would be incompatible.
if (!canBeCastTo(curr->ref->type.getHeapType(), intendedType)) {
// This cast cannot succeed. If the input is not a null, it will
// definitely trap.
if (fallthrough->type.isNonNullable()) {
// Make sure to emit a block with the same type as us; leave updating
// types for other passes.
- std::vector<Expression*> items;
- items.push_back(builder.makeDrop(curr->ref));
- if (curr->rtt) {
- items.push_back(builder.makeDrop(curr->rtt));
- }
- items.push_back(builder.makeUnreachable());
- replaceCurrent(builder.makeBlock(items, curr->type));
+ replaceCurrent(builder.makeBlock(
+ {builder.makeDrop(curr->ref), builder.makeUnreachable()},
+ curr->type));
return;
}
// Otherwise, we are not sure what it is, and need to wait for runtime
@@ -1760,46 +1749,29 @@ struct OptimizeInstructions
// we can see the value is definitely a null at compile time, earlier.)
}
- if (passOptions.ignoreImplicitTraps || passOptions.trapsNeverHappen ||
- !curr->rtt) {
- // Aside from the issue of type incompatibility as mentioned above, the
- // cast can trap if the types *are* compatible but it happens to be the
- // case at runtime that the value is not of the desired subtype. If we
- // do not consider such traps possible, we can ignore that. (Note,
- // though, that we cannot do this if we cannot replace the current type
- // with the reference's type.) We can also do this if this is a static
- // cast: in that case, all we need to know about are the types.
- if (HeapType::isSubType(curr->ref->type.getHeapType(), intendedType)) {
- if (curr->rtt) {
- replaceCurrent(getResultOfFirst(curr->ref,
- builder.makeDrop(curr->rtt),
- getFunction(),
- getModule(),
- passOptions));
- } else {
- replaceCurrent(curr->ref);
+ // Check whether the cast will definitely succeed.
+ if (HeapType::isSubType(curr->ref->type.getHeapType(), intendedType)) {
+ replaceCurrent(curr->ref);
- // We must refinalize here, as we may be returning a more specific
- // type, which can alter the parent. For example:
- //
- // (struct.get $parent 0
- // (ref.cast_static $parent
- // (local.get $child)
- // )
- // )
- //
- // Try to cast a $child to its parent, $parent. That always works,
- // so the cast can be removed.
- // Then once the cast is removed, the outer struct.get
- // will have a reference with a different type, making it a
- // (struct.get $child ..) instead of $parent.
- // But if $parent and $child have different types on field 0 (the
- // child may have a more refined one) then the struct.get must be
- // refinalized so the IR node has the expected type.
- refinalize = true;
- }
- return;
- }
+ // We must refinalize here, as we may be returning a more specific
+ // type, which can alter the parent. For example:
+ //
+ // (struct.get $parent 0
+ // (ref.cast_static $parent
+ // (local.get $child)
+ // )
+ // )
+ //
+ // Try to cast a $child to its parent, $parent. That always works,
+ // so the cast can be removed.
+ // Then once the cast is removed, the outer struct.get
+ // will have a reference with a different type, making it a
+ // (struct.get $child ..) instead of $parent.
+ // But if $parent and $child have different types on field 0 (the
+ // child may have a more refined one) then the struct.get must be
+ // refinalized so the IR node has the expected type.
+ refinalize = true;
+ return;
}
// Repeated identical ref.cast operations are unnecessary. First, find the
@@ -1818,51 +1790,41 @@ struct OptimizeInstructions
}
}
if (auto* child = ref->dynCast<RefCast>()) {
- if (curr->rtt && child->rtt) {
- // Check if the casts are identical.
- if (ExpressionAnalyzer::equal(curr->rtt, child->rtt) &&
- !EffectAnalyzer(passOptions, *getModule(), curr->rtt)
- .hasSideEffects()) {
- replaceCurrent(curr->ref);
+ // Repeated casts can be removed, leaving just the most demanding of
+ // them.
+ auto childIntendedType = child->intendedType;
+ if (HeapType::isSubType(intendedType, childIntendedType)) {
+ // Skip the child.
+ if (curr->ref == child) {
+ curr->ref = child->ref;
return;
+ } else {
+ // The child is not the direct child of the parent, but it is a
+ // fallthrough value, for example,
+ //
+ // (ref.cast parent
+ // (block
+ // .. other code ..
+ // (ref.cast child)))
+ //
+ // In this case it isn't obvious that we can remove the child, as
+ // doing so might require updating the types of the things in the
+ // middle - and in fact the sole purpose of the child may be to get
+ // a proper type for validation to work. Do nothing in this case,
+ // and hope that other opts will help here (for example,
+ // trapsNeverHappen will help if the code validates without the
+ // child).
}
- } else if (!curr->rtt && !child->rtt) {
- // Repeated static casts can be removed, leaving just the most demanding
- // of them.
- auto childIntendedType = child->getIntendedType();
- if (HeapType::isSubType(intendedType, childIntendedType)) {
- // Skip the child.
- if (curr->ref == child) {
- curr->ref = child->ref;
- return;
- } else {
- // The child is not the direct child of the parent, but it is a
- // fallthrough value, for example,
- //
- // (ref.cast parent
- // (block
- // .. other code ..
- // (ref.cast child)))
- //
- // In this case it isn't obvious that we can remove the child, as
- // doing so might require updating the types of the things in the
- // middle - and in fact the sole purpose of the child may be to get
- // a proper type for validation to work. Do nothing in this case,
- // and hope that other opts will help here (for example,
- // trapsNeverHappen will help if the code validates without the
- // child).
- }
- } else if (!canBeCastTo(intendedType, childIntendedType)) {
- // The types are not compatible, so if the input is not null, this
- // will trap.
- if (!curr->type.isNullable()) {
- // Make sure to emit a block with the same type as us; leave
- // updating types for other passes.
- replaceCurrent(builder.makeBlock(
- {builder.makeDrop(curr->ref), builder.makeUnreachable()},
- curr->type));
- return;
- }
+ } else if (!canBeCastTo(intendedType, childIntendedType)) {
+ // The types are not compatible, so if the input is not null, this
+ // will trap.
+ if (!curr->type.isNullable()) {
+ // Make sure to emit a block with the same type as us; leave
+ // updating types for other passes.
+ replaceCurrent(builder.makeBlock(
+ {builder.makeDrop(curr->ref), builder.makeUnreachable()},
+ curr->type));
+ return;
}
}
}
@@ -1905,22 +1867,17 @@ struct OptimizeInstructions
Builder builder(*getModule());
auto refType = curr->ref->type.getHeapType();
- auto intendedType = curr->getIntendedType();
+ auto intendedType = curr->intendedType;
// See above in RefCast.
if (!canBeCastTo(refType, intendedType)) {
// This test cannot succeed, and will definitely return 0.
- std::vector<Expression*> items;
- items.push_back(builder.makeDrop(curr->ref));
- if (curr->rtt) {
- items.push_back(builder.makeDrop(curr->rtt));
- }
- items.push_back(builder.makeConst(int32_t(0)));
- replaceCurrent(builder.makeBlock(items));
+ replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
+ builder.makeConst(int32_t(0))));
return;
}
- if (!curr->rtt && curr->ref->type.isNonNullable() &&
+ if (curr->ref->type.isNonNullable() &&
HeapType::isSubType(refType, intendedType)) {
// This static test will definitely succeed.
replaceCurrent(builder.makeBlock(
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index bbaa6d533..35f218362 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -514,9 +514,8 @@ private:
if (type.isRef()) {
return false;
}
- // For now, don't try to precompute an Rtt. TODO figure out when that would
- // be safe and useful.
- return !type.isRtt();
+
+ return true;
}
};
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 962246569..62dc58c48 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -152,7 +152,6 @@ struct TypeNamePrinter {
void print(const Signature& sig);
void print(const Struct& struct_);
void print(const Array& array);
- void print(const Rtt& rtt);
// FIXME: This hard limit on how many times we call print() avoids extremely
// large outputs, which can be inconveniently large in some cases, but
@@ -179,8 +178,6 @@ void TypeNamePrinter::print(Type type) {
os << type;
} else if (type.isTuple()) {
print(type.getTuple());
- } else if (type.isRtt()) {
- print(type.getRtt());
} else if (type.isRef()) {
if (!maybePrintRefShorthand(os, type)) {
os << "ref";
@@ -301,14 +298,6 @@ void TypeNamePrinter::print(const Array& array) {
os << ']';
}
-void TypeNamePrinter::print(const Rtt& rtt) {
- os << "rtt_";
- if (rtt.hasDepth()) {
- os << rtt.depth << '_';
- }
- print(rtt.heapType);
-}
-
} // anonymous namespace
static std::ostream& printType(std::ostream& o, Type type, Module* wasm) {
@@ -323,14 +312,6 @@ static std::ostream& printType(std::ostream& o, Type type, Module* wasm) {
sep = " ";
}
o << ')';
- } else if (type.isRtt()) {
- auto rtt = type.getRtt();
- o << "(rtt ";
- if (rtt.hasDepth()) {
- o << rtt.depth << ' ';
- }
- TypeNamePrinter(o, wasm).print(rtt.heapType);
- o << ')';
} else if (type.isRef()) {
if (!maybePrintRefShorthand(o, type)) {
o << "(ref ";
@@ -2027,24 +2008,17 @@ struct PrintExpressionContents
}
}
void visitRefTest(RefTest* curr) {
- if (curr->rtt) {
- printMedium(o, "ref.test");
- } else {
- printMedium(o, "ref.test_static ");
- printHeapType(o, curr->intendedType, wasm);
- }
+ printMedium(o, "ref.test_static ");
+ printHeapType(o, curr->intendedType, wasm);
}
+
void visitRefCast(RefCast* curr) {
- if (curr->rtt) {
- printMedium(o, "ref.cast");
+ if (curr->safety == RefCast::Unsafe) {
+ printMedium(o, "ref.cast_nop_static ");
} else {
- if (curr->safety == RefCast::Unsafe) {
- printMedium(o, "ref.cast_nop_static ");
- } else {
- printMedium(o, "ref.cast_static ");
- }
- printHeapType(o, curr->intendedType, wasm);
+ printMedium(o, "ref.cast_static ");
}
+ printHeapType(o, curr->intendedType, wasm);
}
void visitBrOn(BrOn* curr) {
switch (curr->op) {
@@ -2055,27 +2029,17 @@ struct PrintExpressionContents
printMedium(o, "br_on_non_null ");
break;
case BrOnCast:
- if (curr->rtt) {
- printMedium(o, "br_on_cast ");
- } else {
- printMedium(o, "br_on_cast_static ");
- printName(curr->name, o);
- o << ' ';
- printHeapType(o, curr->intendedType, wasm);
- return;
- }
- break;
+ printMedium(o, "br_on_cast_static ");
+ printName(curr->name, o);
+ o << ' ';
+ printHeapType(o, curr->intendedType, wasm);
+ return;
case BrOnCastFail:
- if (curr->rtt) {
- printMedium(o, "br_on_cast_fail ");
- } else {
- printMedium(o, "br_on_cast_static_fail ");
- printName(curr->name, o);
- o << ' ';
- printHeapType(o, curr->intendedType, wasm);
- return;
- }
- break;
+ printMedium(o, "br_on_cast_static_fail ");
+ printName(curr->name, o);
+ o << ' ';
+ printHeapType(o, curr->intendedType, wasm);
+ return;
case BrOnFunc:
printMedium(o, "br_on_func ");
break;
@@ -2099,18 +2063,6 @@ struct PrintExpressionContents
}
printName(curr->name, o);
}
- void visitRttCanon(RttCanon* curr) {
- printMedium(o, "rtt.canon ");
- TypeNamePrinter(o, wasm).print(curr->type.getRtt().heapType);
- }
- void visitRttSub(RttSub* curr) {
- if (curr->fresh) {
- printMedium(o, "rtt.fresh_sub ");
- } else {
- printMedium(o, "rtt.sub ");
- }
- TypeNamePrinter(o, wasm).print(curr->type.getRtt().heapType);
- }
// If we cannot print a valid unreachable instruction (say, a struct.get,
// where if the ref is unreachable, we don't know what heap type to print),
@@ -2135,9 +2087,6 @@ struct PrintExpressionContents
if (curr->isWithDefault()) {
printMedium(o, "_default");
}
- if (curr->rtt) {
- printMedium(o, "_with_rtt");
- }
o << ' ';
TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
@@ -2188,9 +2137,6 @@ struct PrintExpressionContents
if (curr->isWithDefault()) {
printMedium(o, "_default");
}
- if (curr->rtt) {
- printMedium(o, "_with_rtt");
- }
o << ' ';
TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
@@ -2198,10 +2144,7 @@ struct PrintExpressionContents
if (printUnreachableReplacement(curr)) {
return;
}
- printMedium(o, "array.init");
- if (!curr->rtt) {
- printMedium(o, "_static");
- }
+ printMedium(o, "array.init_static");
o << ' ';
TypeNamePrinter(o, wasm).print(curr->type.getHeapType());
}
diff --git a/src/passes/StackIR.cpp b/src/passes/StackIR.cpp
index a3d9442bf..84e19428d 100644
--- a/src/passes/StackIR.cpp
+++ b/src/passes/StackIR.cpp
@@ -72,7 +72,7 @@ public:
// Removing unneeded blocks is dangerous with GC, as if we do this:
//
// (call
- // (rtt)
+ // (struct.new)
// (block
// (nop)
// (i32)
@@ -80,7 +80,7 @@ public:
// )
// === remove inner block ==>
// (call
- // (rtt)
+ // (struct.new)
// (nop)
// (i32)
// )
@@ -90,7 +90,7 @@ public:
// (call
// (block
// (local.set
- // (rtt)
+ // (struct.new)
// )
// (nop)
// (local.get)
@@ -98,7 +98,9 @@ public:
// (i32)
// )
//
- // However, that is not valid as an rtt cannot be set to a local.
+ // However, that is not valid as an non-nullable reference cannot be set to
+ // a local. TODO: double check that this is still true now that we don't
+ // have RTTs.
if (!features.hasGC()) {
removeUnneededBlocks();
}
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index d0c92690a..47d55cfef 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -181,11 +181,11 @@ private:
// Recombination and mutation can replace a node with another node of the same
// type, but should not do so for certain types that are dangerous. For
- // example, it would be bad to add an RTT in a tuple, as that would force us
- // to use temporary locals for the tuple, but RTTs are not defaultable.
- // Also, 'pop' pseudo instruction for EH is supposed to exist only at the
- // beginning of a 'catch' block, so it shouldn't be moved around or deleted
- // freely.
+ // example, it would be bad to add a non-nullable reference to a tuple, as
+ // that would force us to use temporary locals for the tuple, but non-nullable
+ // references cannot always be stored in locals. Also, the 'pop' pseudo
+ // instruction for EH is supposed to exist only at the beginning of a 'catch'
+ // block, so it shouldn't be moved around or deleted freely.
bool canBeArbitrarilyReplaced(Expression* curr) {
return curr->type.isDefaultable() &&
!EHUtils::containsValidDanglingPop(curr);
@@ -312,7 +312,6 @@ private:
bool isLoggableType(Type type);
Nullability getSubType(Nullability nullability);
HeapType getSubType(HeapType type);
- Rtt getSubType(Rtt rtt);
Type getSubType(Type type);
// Utilities
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 59c9dca45..4d0a8d7b7 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -918,7 +918,7 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
&Self::makeSelect)
.add(FeatureSet::Multivalue, &Self::makeTupleExtract);
}
- if (type.isSingle() && !type.isRef() && !type.isRtt()) {
+ if (type.isSingle() && !type.isRef()) {
options.add(FeatureSet::MVP, {&Self::makeLoad, Important});
options.add(FeatureSet::SIMD, &Self::makeSIMD);
}
@@ -1893,8 +1893,6 @@ Expression* TranslateToFuzzReader::makeConst(Type type) {
} else {
return makeConstCompoundRef(type);
}
- } else if (type.isRtt()) {
- return builder.makeRtt(type);
} else if (type.isTuple()) {
std::vector<Expression*> operands;
for (const auto& t : type) {
@@ -2035,14 +2033,15 @@ Expression* TranslateToFuzzReader::makeUnary(Type type) {
// give up
return makeTrivial(type);
}
- // There are no unary ops for reference or RTT types.
- if (type.isRef() || type.isRtt()) {
+ // There are no unary ops for reference types.
+ // TODO: not quite true if you count struct.new and array.new.
+ if (type.isRef()) {
return makeTrivial(type);
}
switch (type.getBasic()) {
case Type::i32: {
auto singleConcreteType = getSingleConcreteType();
- if (singleConcreteType.isRef() || singleConcreteType.isRtt()) {
+ if (singleConcreteType.isRef()) {
// TODO: Do something more interesting here.
return makeTrivial(type);
}
@@ -2241,8 +2240,9 @@ Expression* TranslateToFuzzReader::makeBinary(Type type) {
// give up
return makeTrivial(type);
}
- // There are no binary ops for reference or RTT types.
- if (type.isRef() || type.isRtt()) {
+ // There are no binary ops for reference types.
+ // TODO: Use struct.new
+ if (type.isRef()) {
return makeTrivial(type);
}
switch (type.getBasic()) {
@@ -3056,19 +3056,6 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) {
return type;
}
-Rtt TranslateToFuzzReader::getSubType(Rtt rtt) {
- if (getTypeSystem() == TypeSystem::Nominal ||
- getTypeSystem() == TypeSystem::Isorecursive) {
- // With nominal or isorecursive typing the depth in rtts must match the
- // nominal hierarchy, so we cannot create a random depth like we do below.
- return rtt;
- }
- uint32_t depth = rtt.depth != Rtt::NoDepth
- ? rtt.depth
- : oneIn(2) ? Rtt::NoDepth : upTo(MAX_RTT_DEPTH + 1);
- return Rtt(depth, rtt.heapType);
-}
-
Type TranslateToFuzzReader::getSubType(Type type) {
if (type.isTuple()) {
std::vector<Type> types;
@@ -3080,8 +3067,6 @@ Type TranslateToFuzzReader::getSubType(Type type) {
auto heapType = getSubType(type.getHeapType());
auto nullability = getSubType(type.getNullability());
return Type(heapType, nullability);
- } else if (type.isRtt()) {
- return Type(getSubType(type.getRtt()));
} else {
// This is an MVP type without subtypes.
assert(type.isBasic());
diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp
index edb96977d..364065b8b 100644
--- a/src/tools/fuzzing/heap-types.cpp
+++ b/src/tools/fuzzing/heap-types.cpp
@@ -181,20 +181,12 @@ struct HeapTypeGeneratorImpl {
return builder.getTempRefType(heapType, nullability);
}
- Type generateRttType() {
- auto heapType = generateHeapType();
- auto depth = rand.oneIn(2) ? Rtt::NoDepth : rand.upTo(MAX_RTT_DEPTH);
- return builder.getTempRttType(Rtt(depth, heapType));
- }
-
Type generateSingleType() {
- switch (rand.upTo(3)) {
+ switch (rand.upTo(2)) {
case 0:
return generateBasicType();
case 1:
return generateRefType();
- case 2:
- return generateRttType();
}
WASM_UNREACHABLE("unexpected");
}
@@ -412,20 +404,10 @@ struct HeapTypeGeneratorImpl {
return {pickSubHeapType(super.type), nullability};
}
- Rtt generateSubRtt(Rtt super) {
- auto depth = super.hasDepth()
- ? super.depth
- : rand.oneIn(2) ? Rtt::NoDepth : rand.upTo(MAX_RTT_DEPTH);
- return {depth, super.heapType};
- }
-
Type generateSubtype(Type type) {
if (type.isRef()) {
auto ref = generateSubRef({type.getHeapType(), type.getNullability()});
return builder.getTempRefType(ref.type, ref.nullability);
- } else if (type.isRtt()) {
- auto rtt = generateSubRtt(type.getRtt());
- return builder.getTempRttType(rtt);
} else if (type.isBasic()) {
// Non-reference basic types do not have subtypes.
return type;
diff --git a/src/tools/fuzzing/parameters.h b/src/tools/fuzzing/parameters.h
index 6618ce6db..1ba7b064f 100644
--- a/src/tools/fuzzing/parameters.h
+++ b/src/tools/fuzzing/parameters.h
@@ -38,9 +38,6 @@ constexpr int MAX_TUPLE_SIZE = 6;
// The maximum number of struct fields.
static const int MAX_STRUCT_SIZE = 6;
-// The maximum rtt depth.
-constexpr int MAX_RTT_DEPTH = 3;
-
// The number of nontrivial heap types to generate.
constexpr int MIN_HEAPTYPES = 4;
constexpr int MAX_HEAPTYPES = 20;
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 22fa87633..6150441cd 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -558,7 +558,6 @@ public:
Expression* init;
auto heapType = type.getHeapType();
- // TODO: handle rtts if we need them
if (heapType.isStruct()) {
init = builder.makeStructNew(heapType, args);
} else if (heapType.isArray()) {
diff --git a/src/tools/wasm-fuzz-types.cpp b/src/tools/wasm-fuzz-types.cpp
index d2540636f..d80c89ea8 100644
--- a/src/tools/wasm-fuzz-types.cpp
+++ b/src/tools/wasm-fuzz-types.cpp
@@ -386,24 +386,6 @@ void Fuzzer::checkCanonicalization() {
}
}
- CopiedType getRtt(Type old) {
- auto copied = getChildHeapType(old.getHeapType());
- auto rtt = old.getRtt();
- rtt.heapType = copied.get();
- if (copied.getNew()) {
- // The child is temporary, so we must put it in a temporary type.
- return {NewType{builder.getTempRttType(rtt)}};
- } else {
- // The child is canonical, so we can either put it in a temporary type
- // or use the canonical type.
- if (rand.oneIn(2)) {
- return {NewType{builder.getTempRttType(rtt)}};
- } else {
- return {OldType{Type(rtt)}};
- }
- }
- }
-
CopiedType getRef(Type old) {
auto copied = getChildHeapType(old.getHeapType());
auto type = copied.get();
@@ -425,8 +407,6 @@ void Fuzzer::checkCanonicalization() {
CopiedType getType(Type old) {
if (old.isTuple()) {
return getTuple(old);
- } else if (old.isRtt()) {
- return getRtt(old);
} else if (old.isRef()) {
return getRef(old);
} else {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 200252da7..6b05c38cc 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -373,10 +373,6 @@ enum EncodedType {
nonnullable = -0x15, // 0x6b
// integer reference type
i31ref = -0x16, // 0x6a
- // run-time type info type, with depth index n
- rtt_n = -0x17, // 0x69
- // run-time type info type, without depth index n
- rtt = -0x18, // 0x68
// gc and string reference types
dataref = -0x19, // 0x67
stringref = -0x1c, // 0x64
@@ -1089,36 +1085,24 @@ enum ASTNodes {
// gc opcodes
RefEq = 0xd5,
- StructNewWithRtt = 0x01,
- StructNewDefaultWithRtt = 0x02,
StructGet = 0x03,
StructGetS = 0x04,
StructGetU = 0x05,
StructSet = 0x06,
StructNew = 0x07,
StructNewDefault = 0x08,
- ArrayNewWithRtt = 0x11,
- ArrayNewDefaultWithRtt = 0x12,
ArrayGet = 0x13,
ArrayGetS = 0x14,
ArrayGetU = 0x15,
ArraySet = 0x16,
ArrayLen = 0x17,
ArrayCopy = 0x18,
- ArrayInit = 0x19,
ArrayInitStatic = 0x1a,
ArrayNew = 0x1b,
ArrayNewDefault = 0x1c,
I31New = 0x20,
I31GetS = 0x21,
I31GetU = 0x22,
- RttCanon = 0x30,
- RttSub = 0x31,
- RttFreshSub = 0x32,
- RefTest = 0x40,
- RefCast = 0x41,
- BrOnCast = 0x42,
- BrOnCastFail = 0x43,
RefTestStatic = 0x44,
RefCastStatic = 0x45,
BrOnCastStatic = 0x46,
@@ -1708,8 +1692,6 @@ public:
bool maybeVisitRefTest(Expression*& out, uint32_t code);
bool maybeVisitRefCast(Expression*& out, uint32_t code);
bool maybeVisitBrOn(Expression*& out, uint32_t code);
- bool maybeVisitRttCanon(Expression*& out, uint32_t code);
- bool maybeVisitRttSub(Expression*& out, uint32_t code);
bool maybeVisitStructNew(Expression*& out, uint32_t code);
bool maybeVisitStructGet(Expression*& out, uint32_t code);
bool maybeVisitStructSet(Expression*& out, uint32_t code);
@@ -1755,7 +1737,7 @@ public:
// Struct/Array instructions have an unnecessary heap type that is just for
// validation (except for the case of unreachability, but that's not a problem
- // anyhow, we can ignore it there). That is, we also have a reference / rtt
+ // anyhow, we can ignore it there). That is, we also have a reference typed
// child from which we can infer the type anyhow, and we just need to check
// that type is the same.
void validateHeapTypeUsingChild(Expression* child, HeapType heapType);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 61227a811..1faf95d73 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -805,13 +805,6 @@ public:
ret->finalize();
return ret;
}
- RefTest* makeRefTest(Expression* ref, Expression* rtt) {
- auto* ret = wasm.allocator.alloc<RefTest>();
- ret->ref = ref;
- ret->rtt = rtt;
- ret->finalize();
- return ret;
- }
RefTest* makeRefTest(Expression* ref, HeapType intendedType) {
auto* ret = wasm.allocator.alloc<RefTest>();
ret->ref = ref;
@@ -819,14 +812,6 @@ public:
ret->finalize();
return ret;
}
- RefCast* makeRefCast(Expression* ref, Expression* rtt) {
- auto* ret = wasm.allocator.alloc<RefCast>();
- ret->ref = ref;
- ret->rtt = rtt;
- ret->finalize();
- return ret;
- }
-
RefCast*
makeRefCast(Expression* ref, HeapType intendedType, RefCast::Safety safety) {
auto* ret = wasm.allocator.alloc<RefCast>();
@@ -836,13 +821,11 @@ public:
ret->finalize();
return ret;
}
- BrOn*
- makeBrOn(BrOnOp op, Name name, Expression* ref, Expression* rtt = nullptr) {
+ BrOn* makeBrOn(BrOnOp op, Name name, Expression* ref) {
auto* ret = wasm.allocator.alloc<BrOn>();
ret->op = op;
ret->name = name;
ret->ref = ref;
- ret->rtt = rtt;
ret->finalize();
return ret;
}
@@ -855,37 +838,6 @@ public:
ret->finalize();
return ret;
}
- RttCanon* makeRttCanon(HeapType heapType) {
- auto* ret = wasm.allocator.alloc<RttCanon>();
- ret->type = Type(Rtt(heapType.getDepth(), heapType));
- ret->finalize();
- return ret;
- }
- RttSub* makeRttSub(HeapType heapType, Expression* parent) {
- auto* ret = wasm.allocator.alloc<RttSub>();
- ret->parent = parent;
- auto parentRtt = parent->type.getRtt();
- if (parentRtt.hasDepth()) {
- ret->type = Type(Rtt(parentRtt.depth + 1, heapType));
- } else {
- ret->type = Type(Rtt(heapType));
- }
- ret->finalize();
- return ret;
- }
- RttSub* makeRttFreshSub(HeapType heapType, Expression* parent) {
- auto* ret = makeRttSub(heapType, parent);
- ret->fresh = true;
- return ret;
- }
- template<typename T>
- StructNew* makeStructNew(Expression* rtt, const T& args) {
- auto* ret = wasm.allocator.alloc<StructNew>();
- ret->rtt = rtt;
- ret->operands.set(args);
- ret->finalize();
- return ret;
- }
template<typename T> StructNew* makeStructNew(HeapType type, const T& args) {
auto* ret = wasm.allocator.alloc<StructNew>();
ret->operands.set(args);
@@ -912,15 +864,6 @@ public:
return ret;
}
ArrayNew*
- makeArrayNew(Expression* rtt, Expression* size, Expression* init = nullptr) {
- auto* ret = wasm.allocator.alloc<ArrayNew>();
- ret->rtt = rtt;
- ret->size = size;
- ret->init = init;
- ret->finalize();
- return ret;
- }
- ArrayNew*
makeArrayNew(HeapType type, Expression* size, Expression* init = nullptr) {
auto* ret = wasm.allocator.alloc<ArrayNew>();
ret->size = size;
@@ -929,14 +872,6 @@ public:
ret->finalize();
return ret;
}
- ArrayInit* makeArrayInit(Expression* rtt,
- const std::vector<Expression*>& values) {
- auto* ret = wasm.allocator.alloc<ArrayInit>();
- ret->rtt = rtt;
- ret->values.set(values);
- ret->finalize();
- return ret;
- }
ArrayInit* makeArrayInit(HeapType type,
const std::vector<Expression*>& values) {
auto* ret = wasm.allocator.alloc<ArrayInit>();
@@ -1121,9 +1056,6 @@ public:
if (type.isRef() && type.getHeapType() == HeapType::i31) {
return makeI31New(makeConst(value.geti31()));
}
- if (type.isRtt()) {
- return makeRtt(value.type);
- }
TODO_SINGLE_COMPOUND(type);
WASM_UNREACHABLE("unsupported constant expression");
}
@@ -1141,18 +1073,6 @@ public:
}
}
- // Given a type, creates an RTT expression of that type, using a combination
- // of rtt.canon and rtt.subs.
- Expression* makeRtt(Type type) {
- Expression* ret = makeRttCanon(type.getHeapType());
- if (type.getRtt().hasDepth()) {
- for (Index i = 0; i < type.getRtt().depth; i++) {
- ret = makeRttSub(type.getHeapType(), ret);
- }
- }
- return ret;
- }
-
// Additional utility functions for building on top of nodes
// Convenient to have these on Builder, as it has allocation built in
@@ -1322,25 +1242,13 @@ public:
ValidatingBuilder(Module& wasm, size_t line, size_t col)
: Builder(wasm), line(line), col(col) {}
- Expression* validateAndMakeBrOn(BrOnOp op,
- Name name,
- Expression* ref,
- Expression* rtt = nullptr) {
- if (op == BrOnCast) {
- if (rtt->type == Type::unreachable) {
- // An unreachable rtt is not supported: the text and binary formats do
- // not provide the type, so if it's unreachable we should not even
- // create a br_on_cast in such a case, as we'd have no idea what it
- // casts to.
- return makeSequence(makeDrop(ref), rtt);
- }
- }
+ Expression* validateAndMakeBrOn(BrOnOp op, Name name, Expression* ref) {
if (op == BrOnNull) {
if (!ref->type.isRef() && ref->type != Type::unreachable) {
throw ParseException("Invalid ref for br_on_null", line, col);
}
}
- return makeBrOn(op, name, ref, rtt);
+ return makeBrOn(op, name, ref);
}
template<typename T>
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index 55a9edd16..fa1fa229f 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -601,7 +601,6 @@ switch (DELEGATE_ID) {
case Expression::Id::RefTestId: {
DELEGATE_START(RefTest);
DELEGATE_FIELD_HEAPTYPE(RefTest, intendedType);
- DELEGATE_FIELD_OPTIONAL_CHILD(RefTest, rtt);
DELEGATE_FIELD_CHILD(RefTest, ref);
DELEGATE_END(RefTest);
break;
@@ -609,7 +608,6 @@ switch (DELEGATE_ID) {
case Expression::Id::RefCastId: {
DELEGATE_START(RefCast);
DELEGATE_FIELD_HEAPTYPE(RefCast, intendedType);
- DELEGATE_FIELD_OPTIONAL_CHILD(RefCast, rtt);
DELEGATE_FIELD_CHILD(RefCast, ref);
DELEGATE_END(RefCast);
break;
@@ -619,26 +617,12 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_INT(BrOn, op);
DELEGATE_FIELD_SCOPE_NAME_USE(BrOn, name);
DELEGATE_FIELD_HEAPTYPE(BrOn, intendedType);
- DELEGATE_FIELD_OPTIONAL_CHILD(BrOn, rtt);
DELEGATE_FIELD_CHILD(BrOn, ref);
DELEGATE_END(BrOn);
break;
}
- case Expression::Id::RttCanonId: {
- DELEGATE_START(RttCanon);
- DELEGATE_END(RttCanon);
- break;
- }
- case Expression::Id::RttSubId: {
- DELEGATE_START(RttSub);
- DELEGATE_FIELD_CHILD(RttSub, parent);
- DELEGATE_FIELD_INT(RttSub, fresh);
- DELEGATE_END(RttSub);
- break;
- }
case Expression::Id::StructNewId: {
DELEGATE_START(StructNew);
- DELEGATE_FIELD_OPTIONAL_CHILD(StructNew, rtt);
DELEGATE_FIELD_CHILD_VECTOR(StructNew, operands);
DELEGATE_END(StructNew);
break;
@@ -661,7 +645,6 @@ switch (DELEGATE_ID) {
}
case Expression::Id::ArrayNewId: {
DELEGATE_START(ArrayNew);
- DELEGATE_FIELD_OPTIONAL_CHILD(ArrayNew, rtt);
DELEGATE_FIELD_CHILD(ArrayNew, size);
DELEGATE_FIELD_OPTIONAL_CHILD(ArrayNew, init);
DELEGATE_END(ArrayNew);
@@ -669,7 +652,6 @@ switch (DELEGATE_ID) {
}
case Expression::Id::ArrayInitId: {
DELEGATE_START(ArrayInit);
- DELEGATE_FIELD_OPTIONAL_CHILD(ArrayInit, rtt);
DELEGATE_FIELD_CHILD_VECTOR(ArrayInit, values);
DELEGATE_END(ArrayInit);
break;
diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def
index 24531b149..b88a55556 100644
--- a/src/wasm-delegations.def
+++ b/src/wasm-delegations.def
@@ -73,8 +73,6 @@ DELEGATE(CallRef);
DELEGATE(RefTest);
DELEGATE(RefCast);
DELEGATE(BrOn);
-DELEGATE(RttCanon);
-DELEGATE(RttSub);
DELEGATE(StructNew);
DELEGATE(StructGet);
DELEGATE(StructSet);
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index d00ccac43..254a1a2e2 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1467,19 +1467,6 @@ public:
if (ref.breaking()) {
return typename Cast::Breaking{ref};
}
- // The RTT value for the type we are trying to cast to.
- Literal intendedRtt;
- if (curr->rtt) {
- // This is a dynamic check with an RTT.
- Flow rtt = self()->visit(curr->rtt);
- if (rtt.breaking()) {
- return typename Cast::Breaking{rtt};
- }
- intendedRtt = rtt.getSingleValue();
- } else {
- // If there is no explicit RTT, use the canonical RTT for the static type.
- intendedRtt = Literal::makeCanonicalRtt(curr->intendedType);
- }
Literal original = ref.getSingleValue();
if (original.isNull()) {
return typename Cast::Null{original};
@@ -1489,30 +1476,10 @@ public:
if (!original.isData() && !original.isFunction()) {
return typename Cast::Failure{original};
}
- Literal actualRtt;
- if (original.isFunction()) {
- // Function references always have the canonical RTTs of the functions
- // they reference. We must have a module to look up the function's type to
- // get that canonical RTT.
- auto* func =
- module ? module->getFunctionOrNull(original.getFunc()) : nullptr;
- if (!func) {
- return typename Cast::Breaking{NONCONSTANT_FLOW};
- }
- actualRtt = Literal::makeCanonicalRtt(func->type);
- } else {
- assert(original.isData());
- actualRtt = original.getGCData()->rtt;
- };
- // We have the actual and intended RTTs, so perform the cast.
- if (actualRtt.isSubRtt(intendedRtt)) {
- HeapType resultType = intendedRtt.type.getHeapType();
- if (original.isFunction()) {
- return typename Cast::Success{Literal{original.getFunc(), resultType}};
- } else {
- return
- typename Cast::Success{Literal(original.getGCData(), resultType)};
- }
+ HeapType actualType = original.type.getHeapType();
+ // We have the actual and intended types, so perform the cast.
+ if (HeapType::isSubType(actualType, curr->intendedType)) {
+ return typename Cast::Success{original};
} else {
return typename Cast::Failure{original};
}
@@ -1629,33 +1596,8 @@ public:
}
return {value};
}
- Flow visitRttCanon(RttCanon* curr) {
- return Literal::makeCanonicalRtt(curr->type.getHeapType());
- }
- Flow visitRttSub(RttSub* curr) {
- Flow parent = self()->visit(curr->parent);
- if (parent.breaking()) {
- return parent;
- }
- auto parentValue = parent.getSingleValue();
- auto newSupers = std::make_unique<RttSupers>(parentValue.getRttSupers());
- newSupers->push_back(parentValue.type.getHeapType());
- if (curr->fresh) {
- newSupers->back().makeFresh();
- }
- return Literal(std::move(newSupers), curr->type);
- }
-
Flow visitStructNew(StructNew* curr) {
NOTE_ENTER("StructNew");
- Literal rttVal;
- if (curr->rtt) {
- Flow rtt = self()->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
- }
- rttVal = rtt.getSingleValue();
- }
if (curr->type == Type::unreachable) {
// We cannot proceed to compute the heap type, as there isn't one. Just
// find why we are unreachable, and stop there.
@@ -1681,10 +1623,7 @@ public:
data[i] = value.getSingleValue();
}
}
- if (!curr->rtt) {
- rttVal = Literal::makeCanonicalRtt(heapType);
- }
- return Literal(std::make_shared<GCData>(rttVal, data),
+ return Literal(std::make_shared<GCData>(curr->type.getHeapType(), data),
curr->type.getHeapType());
}
Flow visitStructGet(StructGet* curr) {
@@ -1728,14 +1667,6 @@ public:
Flow visitArrayNew(ArrayNew* curr) {
NOTE_ENTER("ArrayNew");
- Literal rttVal;
- if (curr->rtt) {
- Flow rtt = self()->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
- }
- rttVal = rtt.getSingleValue();
- }
auto size = self()->visit(curr->size);
if (size.breaking()) {
return size;
@@ -1769,22 +1700,11 @@ public:
data[i] = value;
}
}
- if (!curr->rtt) {
- rttVal = Literal::makeCanonicalRtt(heapType);
- }
- return Literal(std::make_shared<GCData>(rttVal, data),
+ return Literal(std::make_shared<GCData>(curr->type.getHeapType(), data),
curr->type.getHeapType());
}
Flow visitArrayInit(ArrayInit* curr) {
NOTE_ENTER("ArrayInit");
- Literal rttVal;
- if (curr->rtt) {
- Flow rtt = self()->visit(curr->rtt);
- if (rtt.breaking()) {
- return rtt;
- }
- rttVal = rtt.getSingleValue();
- }
Index num = curr->values.size();
if (num >= ArrayLimit) {
hostLimit("allocation failure");
@@ -1810,10 +1730,7 @@ public:
}
data[i] = truncateForPacking(value.getSingleValue(), field);
}
- if (!curr->rtt) {
- rttVal = Literal::makeCanonicalRtt(heapType);
- }
- return Literal(std::make_shared<GCData>(rttVal, data),
+ return Literal(std::make_shared<GCData>(curr->type.getHeapType(), data),
curr->type.getHeapType());
}
Flow visitArrayGet(ArrayGet* curr) {
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 0829a35f2..64f764721 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -279,24 +279,16 @@ private:
Expression* makeCallRef(Element& s, bool isReturn);
Expression* makeI31New(Element& s);
Expression* makeI31Get(Element& s, bool signed_);
- Expression* makeRefTest(Element& s);
Expression* makeRefTestStatic(Element& s);
- Expression* makeRefCast(Element& s);
Expression* makeRefCastStatic(Element& s);
Expression* makeRefCastNopStatic(Element& s);
Expression* makeBrOn(Element& s, BrOnOp op);
Expression* makeBrOnStatic(Element& s, BrOnOp op);
- Expression* makeRttCanon(Element& s);
- Expression* makeRttSub(Element& s);
- Expression* makeRttFreshSub(Element& s);
- Expression* makeStructNew(Element& s, bool default_);
Expression* makeStructNewStatic(Element& s, bool default_);
Index getStructIndex(Element& type, Element& field);
Expression* makeStructGet(Element& s, bool signed_ = false);
Expression* makeStructSet(Element& s);
- Expression* makeArrayNew(Element& s, bool default_);
Expression* makeArrayNewStatic(Element& s, bool default_);
- Expression* makeArrayInit(Element& s);
Expression* makeArrayInitStatic(Element& s);
Expression* makeArrayGet(Element& s, bool signed_ = false);
Expression* makeArraySet(Element& s);
@@ -359,7 +351,7 @@ private:
// Struct/Array instructions have an unnecessary heap type that is just for
// validation (except for the case of unreachability, but that's not a problem
- // anyhow, we can ignore it there). That is, we also have a reference / rtt
+ // anyhow, we can ignore it there). That is, we also have a reference typed
// child from which we can infer the type anyhow, and we just need to check
// that type is the same.
void
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 4d87ac68d..014e28646 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -67,7 +67,6 @@ struct Signature;
struct Field;
struct Struct;
struct Array;
-struct Rtt;
enum Nullability { NonNullable, Nullable };
enum Mutability { Immutable, Mutable };
@@ -128,9 +127,6 @@ public:
// Signature, Struct or Array via implicit conversion to HeapType.
Type(HeapType, Nullability nullable);
- // Construct from rtt description
- Type(Rtt);
-
// Predicates
// Compound Concrete
// Type Basic │ Single│
@@ -152,7 +148,6 @@ public:
// ├─ Compound ──╫───┼───┼───┼───┤───────┤ │
// │ Ref ║ │ x │ x │ x │ f? n? │◄┘
// │ Tuple ║ │ x │ │ x │ │
- // │ Rtt ║ │ x │ x │ x │ │
// └─────────────╨───┴───┴───┴───┴───────┘
constexpr bool isBasic() const { return id <= _last_basic_type; }
constexpr bool isConcrete() const { return id >= i32; }
@@ -174,18 +169,10 @@ public:
// is irrelevant. (For that reason, this is only the negation of isNullable()
// on references, but both return false on non-references.)
bool isNonNullable() const;
- bool isRtt() const;
bool isStruct() const;
bool isArray() const;
bool isDefaultable() const;
- // Check if a type is either defaultable or non-nullable. This is useful in
- // the case where we allow non-nullable types, but we disallow other things
- // that are non-defaultable. For example, when GC-non-nullable references are
- // allowed we can have a non-nullable reference, but we cannot have any other
- // nondefaultable type.
- bool isDefaultableOrNonNullable() const;
-
Nullability getNullability() const;
private:
@@ -237,12 +224,9 @@ public:
const Tuple& getTuple() const;
// Gets the heap type corresponding to this type, assuming that it is a
- // reference or Rtt type.
+ // reference type.
HeapType getHeapType() const;
- // Gets the Rtt for this type, assuming that it is an Rtt type.
- Rtt getRtt() const;
-
// Returns a number type based on its size in bytes and whether it is a float
// type.
static Type get(unsigned byteSize, bool float_);
@@ -561,21 +545,6 @@ struct Array {
std::string toString() const;
};
-struct Rtt {
- // An Rtt can have no depth specified
- static constexpr uint32_t NoDepth = -1;
- uint32_t depth;
- HeapType heapType;
- explicit Rtt(HeapType heapType) : depth(NoDepth), heapType(heapType) {}
- Rtt(uint32_t depth, HeapType heapType) : depth(depth), heapType(heapType) {}
- bool operator==(const Rtt& other) const {
- return depth == other.depth && heapType == other.heapType;
- }
- bool operator!=(const Rtt& other) const { return !(*this == other); }
- bool hasDepth() const { return depth != uint32_t(NoDepth); }
- std::string toString() const;
-};
-
// TypeBuilder - allows for the construction of recursive types. Contains a
// table of `n` mutable HeapTypes and can construct temporary types that are
// backed by those HeapTypes, refering to them by reference. Those temporary
@@ -623,11 +592,10 @@ struct TypeBuilder {
HeapType getTempHeapType(size_t i);
// Gets a temporary type or heap type for use in initializing the
- // TypeBuilder's HeapTypes. For Ref and Rtt types, the HeapType may be a
- // temporary HeapType owned by this builder or a canonical HeapType.
+ // TypeBuilder's HeapTypes. For Ref types, the HeapType may be a temporary
+ // HeapType owned by this builder or a canonical HeapType.
Type getTempTupleType(const Tuple&);
Type getTempRefType(HeapType heapType, Nullability nullable);
- Type getTempRttType(Rtt rtt);
// In nominal mode, or for nominal types, declare the HeapType being built at
// index `i` to be an immediate subtype of the HeapType being built at index
@@ -717,7 +685,6 @@ std::ostream& operator<<(std::ostream&, Signature);
std::ostream& operator<<(std::ostream&, Field);
std::ostream& operator<<(std::ostream&, Struct);
std::ostream& operator<<(std::ostream&, Array);
-std::ostream& operator<<(std::ostream&, Rtt);
std::ostream& operator<<(std::ostream&, TypeBuilder::ErrorReason);
} // namespace wasm
@@ -752,10 +719,6 @@ template<> class hash<wasm::HeapType> {
public:
size_t operator()(const wasm::HeapType&) const;
};
-template<> class hash<wasm::Rtt> {
-public:
- size_t operator()(const wasm::Rtt&) const;
-};
template<> class hash<wasm::RecGroup> {
public:
size_t operator()(const wasm::RecGroup&) const;
diff --git a/src/wasm.h b/src/wasm.h
index 8c0e48da2..d0f632829 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -712,8 +712,6 @@ public:
RefTestId,
RefCastId,
BrOnId,
- RttCanonId,
- RttSubId,
StructNewId,
StructGetId,
StructSetId,
@@ -1492,16 +1490,9 @@ public:
Expression* ref;
- // If rtt is provided then this is a dynamic test with an rtt. If nullptr then
- // this is a static cast and intendedType is set, and it contains the type we
- // intend to cast to.
- Expression* rtt = nullptr;
HeapType intendedType;
void finalize();
-
- // Returns the type we intend to cast to.
- HeapType getIntendedType();
};
class RefCast : public SpecificExpression<Expression::RefCastId> {
@@ -1510,8 +1501,6 @@ public:
Expression* ref;
- // See above with RefTest.
- Expression* rtt = nullptr;
HeapType intendedType;
// Support the unsafe `ref.cast_nop_static` to enable precise cast overhead
@@ -1520,9 +1509,6 @@ public:
Safety safety = Safe;
void finalize();
-
- // Returns the type we intend to cast to.
- HeapType getIntendedType();
};
class BrOn : public SpecificExpression<Expression::BrOnId> {
@@ -1533,55 +1519,18 @@ public:
Name name;
Expression* ref;
- // BrOnCast* has, like RefCast and RefTest, either an rtt or a static intended
- // type.
- Expression* rtt = nullptr;
HeapType intendedType;
- // TODO: BrOnNull also has an optional extra value in the spec, which we do
- // not support. See also the discussion on
- // https://github.com/WebAssembly/function-references/issues/45
- // - depending on the decision there, we may want to move BrOnNull into
- // Break or a new class of its own.
-
void finalize();
- // Returns the type we intend to cast to. Relevant only for the cast variants.
- HeapType getIntendedType();
-
// Returns the type sent on the branch, if it is taken.
Type getSentType();
};
-class RttCanon : public SpecificExpression<Expression::RttCanonId> {
-public:
- RttCanon(MixedArena& allocator) {}
-
- void finalize();
-};
-
-class RttSub : public SpecificExpression<Expression::RttSubId> {
-public:
- RttSub(MixedArena& allocator) {}
-
- Expression* parent;
-
- // rtt.fresh_sub is like rtt.sub, but never caching or canonicalizing (i.e.,
- // it always returns a fresh RTT, non-identical to any other RTT in the
- // system).
- bool fresh = false;
-
- void finalize();
-};
-
class StructNew : public SpecificExpression<Expression::StructNewId> {
public:
StructNew(MixedArena& allocator) : operands(allocator) {}
- // A dynamic StructNew has an rtt, while a static one declares the type using
- // the type field.
- Expression* rtt = nullptr;
-
// A struct.new_with_default has empty operands. This does leave the case of a
// struct with no fields ambiguous, but it doesn't make a difference in that
// case, and binaryen doesn't guarantee roundtripping binaries anyhow.
@@ -1625,10 +1574,6 @@ public:
Expression* init = nullptr;
Expression* size;
- // A dynamic ArrayNew has an rtt, while a static one declares the type using
- // the type field.
- Expression* rtt = nullptr;
-
bool isWithDefault() { return !init; }
void finalize();
@@ -1640,10 +1585,6 @@ public:
ExpressionList values;
- // A dynamic ArrayInit has an rtt, while a static one declares the type using
- // the type field.
- Expression* rtt = nullptr;
-
void finalize();
};
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index b8a6c7e7a..05f9d93d5 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -53,8 +53,6 @@ Literal::Literal(Type type) : type(type) {
if (isData()) {
assert(!type.isNonNullable());
new (&gcData) std::shared_ptr<GCData>();
- } else if (type.isRtt()) {
- new (this) Literal(Literal::makeCanonicalRtt(type.getHeapType()));
} else {
// For anything else, zero out all the union data.
memset(&v128, 0, 16);
@@ -71,11 +69,6 @@ Literal::Literal(std::shared_ptr<GCData> gcData, HeapType type)
assert(isData());
}
-Literal::Literal(std::unique_ptr<RttSupers>&& rttSupers, Type type)
- : rttSupers(std::move(rttSupers)), type(type) {
- assert(type.isRtt());
-}
-
Literal::Literal(const Literal& other) : type(other.type) {
if (type.isBasic()) {
switch (type.getBasic()) {
@@ -104,11 +97,6 @@ Literal::Literal(const Literal& other) : type(other.type) {
func = other.func;
return;
}
- if (type.isRtt()) {
- // Allocate a new RttSupers with a copy of the other's data.
- new (&rttSupers) auto(std::make_unique<RttSupers>(*other.rttSupers));
- return;
- }
if (type.isRef()) {
auto heapType = type.getHeapType();
if (heapType.isBasic()) {
@@ -136,11 +124,8 @@ Literal::~Literal() {
if (type.isBasic()) {
return;
}
-
if (isData()) {
gcData.~shared_ptr();
- } else if (type.isRtt()) {
- rttSupers.~unique_ptr();
}
}
@@ -152,18 +137,6 @@ Literal& Literal::operator=(const Literal& other) {
return *this;
}
-Literal Literal::makeCanonicalRtt(HeapType type) {
- auto supers = std::make_unique<RttSupers>();
- std::optional<HeapType> supertype;
- for (auto curr = type; (supertype = curr.getSuperType()); curr = *supertype) {
- supers->emplace_back(*supertype);
- }
- // We want the highest types to be first.
- std::reverse(supers->begin(), supers->end());
- size_t depth = supers->size();
- return Literal(std::move(supers), Type(Rtt(depth, type)));
-}
-
template<typename LaneT, int Lanes>
static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
std::array<uint8_t, 16> bytes;
@@ -228,8 +201,6 @@ Literal Literal::makeZero(Type type) {
assert(type.isSingle());
if (type.isRef()) {
return makeNull(type.getHeapType());
- } else if (type.isRtt()) {
- return Literal(type);
} else {
return makeFromInt32(0, type);
}
@@ -257,11 +228,6 @@ std::shared_ptr<GCData> Literal::getGCData() const {
return gcData;
}
-const RttSupers& Literal::getRttSupers() const {
- assert(type.isRtt());
- return *rttSupers;
-}
-
Literal Literal::castToF32() {
assert(type == Type::i32);
Literal ret(Type::f32);
@@ -383,8 +349,6 @@ bool Literal::operator==(const Literal& other) const {
// other non-null reference type literals cannot represent concrete values,
// i.e. there is no concrete anyref or eqref other than null.
WASM_UNREACHABLE("unexpected type");
- } else if (type.isRtt()) {
- return *rttSupers == *other.rttSupers;
}
WASM_UNREACHABLE("unexpected type");
}
@@ -494,7 +458,7 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
if (literal.isData()) {
auto data = literal.getGCData();
if (data) {
- o << "[ref " << data->rtt << ' ' << data->values << ']';
+ o << "[ref " << data->type << ' ' << data->values << ']';
} else {
o << "[ref null " << literal.type << ']';
}
@@ -524,15 +488,6 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
WASM_UNREACHABLE("type should have been handled above");
}
}
- } else if (literal.type.isRtt()) {
- o << "[rtt ";
- for (auto& super : literal.getRttSupers()) {
- o << super.type << " :> ";
- if (super.freshPtr) {
- o << " (fresh)";
- }
- }
- o << literal.type << ']';
} else {
TODO_SINGLE_COMPOUND(literal.type);
switch (literal.type.getBasic()) {
@@ -2564,31 +2519,4 @@ Literal Literal::relaxedFmsF64x2(const Literal& left,
return ternary<2, &Literal::getLanesF64x2, &Literal::fms>(*this, left, right);
}
-bool Literal::isSubRtt(const Literal& other) const {
- assert(type.isRtt() && other.type.isRtt());
- // For this literal to be a sub-rtt of the other rtt, the supers must be a
- // superset. That is, if other is a->b->c then we should be a->b->c as well
- // with possibly ->d->.. added. The rttSupers array represents those chains,
- // but only the supers, which means the last item in the chain is simply the
- // type of the literal.
- const auto& supers = getRttSupers();
- const auto& otherSupers = other.getRttSupers();
- if (otherSupers.size() > supers.size()) {
- return false;
- }
- for (Index i = 0; i < otherSupers.size(); i++) {
- if (supers[i] != otherSupers[i]) {
- return false;
- }
- }
- // If we have more supers than other, compare that extra super. Otherwise,
- // we have the same amount of supers, and must be completely identical to
- // other.
- if (otherSupers.size() < supers.size()) {
- return other.type.getHeapType() == supers[otherSupers.size()].type;
- } else {
- return other.type == type;
- }
-}
-
} // namespace wasm
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 4e8e3f0d7..b74ef017b 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1383,17 +1383,6 @@ void WasmBinaryWriter::writeType(Type type) {
writeHeapType(type.getHeapType());
return;
}
- if (type.isRtt()) {
- auto rtt = type.getRtt();
- if (rtt.hasDepth()) {
- o << S32LEB(BinaryConsts::EncodedType::rtt_n);
- o << U32LEB(rtt.depth);
- } else {
- o << S32LEB(BinaryConsts::EncodedType::rtt);
- }
- writeIndexedHeapType(rtt.heapType);
- return;
- }
int ret = 0;
TODO_SINGLE_COMPOUND(type);
switch (type.getBasic()) {
@@ -1877,14 +1866,6 @@ Type WasmBinaryBuilder::getType(int initial) {
return Type(getHeapType(), Nullable);
case BinaryConsts::EncodedType::nonnullable:
return Type(getHeapType(), NonNullable);
- case BinaryConsts::EncodedType::rtt_n: {
- auto depth = getU32LEB();
- auto heapType = getIndexedHeapType();
- return Type(Rtt(depth, heapType));
- }
- case BinaryConsts::EncodedType::rtt: {
- return Type(Rtt(getIndexedHeapType()));
- }
default:
throwError("invalid wasm type: " + std::to_string(initial));
}
@@ -2029,16 +2010,6 @@ void WasmBinaryBuilder::readTypes() {
}
return builder.getTempRefType(builder[size_t(htCode)], nullability);
}
- case BinaryConsts::EncodedType::rtt_n:
- case BinaryConsts::EncodedType::rtt: {
- auto depth = typeCode == BinaryConsts::EncodedType::rtt ? Rtt::NoDepth
- : getU32LEB();
- auto htCode = getU32LEB();
- if (size_t(htCode) >= builder.size()) {
- throwError("invalid type index: " + std::to_string(htCode));
- }
- return builder.getTempRttType(Rtt(depth, builder[htCode]));
- }
default:
throwError("unexpected type index: " + std::to_string(typeCode));
}
@@ -3875,12 +3846,6 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitBrOn(curr, opcode)) {
break;
}
- if (maybeVisitRttCanon(curr, opcode)) {
- break;
- }
- if (maybeVisitRttSub(curr, opcode)) {
- break;
- }
if (maybeVisitStructNew(curr, opcode)) {
break;
}
@@ -6793,12 +6758,7 @@ bool WasmBinaryBuilder::maybeVisitI31Get(Expression*& out, uint32_t code) {
}
bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) {
- if (code == BinaryConsts::RefTest) {
- auto* rtt = popNonVoidExpression();
- auto* ref = popNonVoidExpression();
- out = Builder(wasm).makeRefTest(ref, rtt);
- return true;
- } else if (code == BinaryConsts::RefTestStatic) {
+ if (code == BinaryConsts::RefTestStatic) {
auto intendedType = getIndexedHeapType();
auto* ref = popNonVoidExpression();
out = Builder(wasm).makeRefTest(ref, intendedType);
@@ -6808,13 +6768,8 @@ bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) {
}
bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) {
- if (code == BinaryConsts::RefCast) {
- auto* rtt = popNonVoidExpression();
- auto* ref = popNonVoidExpression();
- out = Builder(wasm).makeRefCast(ref, rtt);
- return true;
- } else if (code == BinaryConsts::RefCastStatic ||
- code == BinaryConsts::RefCastNopStatic) {
+ if (code == BinaryConsts::RefCastStatic ||
+ code == BinaryConsts::RefCastNopStatic) {
auto intendedType = getIndexedHeapType();
auto* ref = popNonVoidExpression();
auto safety =
@@ -6834,11 +6789,9 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) {
case BinaryConsts::BrOnNonNull:
op = BrOnNonNull;
break;
- case BinaryConsts::BrOnCast:
case BinaryConsts::BrOnCastStatic:
op = BrOnCast;
break;
- case BinaryConsts::BrOnCastFail:
case BinaryConsts::BrOnCastStaticFail:
op = BrOnCastFail;
break;
@@ -6871,35 +6824,8 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) {
out = Builder(wasm).makeBrOn(op, name, ref, intendedType);
return true;
}
- Expression* rtt = nullptr;
- if (op == BrOnCast || op == BrOnCastFail) {
- rtt = popNonVoidExpression();
- }
auto* ref = popNonVoidExpression();
- out = ValidatingBuilder(wasm, pos).validateAndMakeBrOn(op, name, ref, rtt);
- return true;
-}
-
-bool WasmBinaryBuilder::maybeVisitRttCanon(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::RttCanon) {
- return false;
- }
- auto heapType = getIndexedHeapType();
- out = Builder(wasm).makeRttCanon(heapType);
- return true;
-}
-
-bool WasmBinaryBuilder::maybeVisitRttSub(Expression*& out, uint32_t code) {
- if (code != BinaryConsts::RttSub && code != BinaryConsts::RttFreshSub) {
- return false;
- }
- auto targetHeapType = getIndexedHeapType();
- auto* parent = popNonVoidExpression();
- if (code == BinaryConsts::RttSub) {
- out = Builder(wasm).makeRttSub(targetHeapType, parent);
- } else {
- out = Builder(wasm).makeRttFreshSub(targetHeapType, parent);
- }
+ out = ValidatingBuilder(wasm, pos).validateAndMakeBrOn(op, name, ref);
return true;
}
@@ -6917,21 +6843,6 @@ bool WasmBinaryBuilder::maybeVisitStructNew(Expression*& out, uint32_t code) {
}
out = Builder(wasm).makeStructNew(heapType, operands);
return true;
- } else if (code == BinaryConsts::StructNewWithRtt ||
- code == BinaryConsts::StructNewDefaultWithRtt) {
- auto heapType = getIndexedHeapType();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- std::vector<Expression*> operands;
- if (code == BinaryConsts::StructNewWithRtt) {
- auto numOperands = heapType.getStruct().fields.size();
- operands.resize(numOperands);
- for (Index i = 0; i < numOperands; i++) {
- operands[numOperands - i - 1] = popNonVoidExpression();
- }
- }
- out = Builder(wasm).makeStructNew(rtt, operands);
- return true;
}
return false;
}
@@ -6987,18 +6898,6 @@ bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) {
}
out = Builder(wasm).makeArrayNew(heapType, size, init);
return true;
- } else if (code == BinaryConsts::ArrayNewWithRtt ||
- code == BinaryConsts::ArrayNewDefaultWithRtt) {
- auto heapType = getIndexedHeapType();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- auto* size = popNonVoidExpression();
- Expression* init = nullptr;
- if (code == BinaryConsts::ArrayNewWithRtt) {
- init = popNonVoidExpression();
- }
- out = Builder(wasm).makeArrayNew(rtt, size, init);
- return true;
}
return false;
}
@@ -7013,17 +6912,6 @@ bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) {
}
out = Builder(wasm).makeArrayInit(heapType, values);
return true;
- } else if (code == BinaryConsts::ArrayInit) {
- auto heapType = getIndexedHeapType();
- auto size = getU32LEB();
- auto* rtt = popNonVoidExpression();
- validateHeapTypeUsingChild(rtt, heapType);
- std::vector<Expression*> values(size);
- for (size_t i = 0; i < size; i++) {
- values[size - i - 1] = popNonVoidExpression();
- }
- out = Builder(wasm).makeArrayInit(rtt, values);
- return true;
}
return false;
}
@@ -7370,7 +7258,7 @@ void WasmBinaryBuilder::validateHeapTypeUsingChild(Expression* child,
if (child->type == Type::unreachable) {
return;
}
- if ((!child->type.isRef() && !child->type.isRtt()) ||
+ if (!child->type.isRef() ||
!HeapType::isSubType(child->type.getHeapType(), heapType)) {
throwError("bad heap type: expected " + heapType.toString() +
" but found " + child->type.toString());
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 38ec788ba..f13091c91 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -54,7 +54,7 @@ namespace wasm {
static Name STRUCT("struct"), FIELD("field"), ARRAY("array"),
FUNC_SUBTYPE("func_subtype"), STRUCT_SUBTYPE("struct_subtype"),
ARRAY_SUBTYPE("array_subtype"), EXTENDS("extends"), REC("rec"), I8("i8"),
- I16("i16"), RTT("rtt"), DECLARE("declare"), ITEM("item"), OFFSET("offset");
+ I16("i16"), DECLARE("declare"), ITEM("item"), OFFSET("offset");
static Address getAddress(const Element* s) { return atoll(s->c_str()); }
@@ -752,46 +752,11 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) {
}
};
- auto parseRttType = [&](Element& elem) -> Type {
- // '(' 'rtt' depth? typeidx ')'
- uint32_t depth;
- Element* idx;
- switch (elem.size()) {
- default:
- throw ParseException(
- "unexpected number of rtt parameters", elem.line, elem.col);
- case 2:
- depth = Rtt::NoDepth;
- idx = elem[1];
- break;
- case 3:
- if (!String::isNumber(elem[1]->c_str())) {
- throw ParseException(
- "invalid rtt depth", elem[1]->line, elem[1]->col);
- }
- depth = atoi(elem[1]->c_str());
- idx = elem[2];
- break;
- }
- if (idx->dollared()) {
- HeapType type = builder[typeIndices[idx->c_str()]];
- return builder.getTempRttType(Rtt(depth, type));
- } else if (String::isNumber(idx->c_str())) {
- size_t index = atoi(idx->c_str());
- if (index < numTypes) {
- return builder.getTempRttType(Rtt(depth, builder[index]));
- }
- }
- throw ParseException("invalid type index", idx->line, idx->col);
- };
-
auto parseValType = [&](Element& elem) {
if (elem.isStr()) {
return stringToType(elem.c_str());
} else if (*elem[0] == REF) {
return parseRefType(elem);
- } else if (*elem[0] == RTT) {
- return parseRttType(elem);
} else {
throw ParseException("unknown valtype kind", elem[0]->line, elem[0]->col);
}
@@ -1281,18 +1246,6 @@ Type SExpressionWasmBuilder::elementToType(Element& s) {
}
return Type(parseHeapType(*s[i]), nullable);
}
- if (elementStartsWith(s, RTT)) {
- // It's an RTT, something like (rtt N $typename) or just (rtt $typename)
- // if there is no depth.
- if (s[1]->dollared()) {
- auto heapType = parseHeapType(*s[1]);
- return Type(Rtt(heapType));
- } else {
- auto depth = atoi(s[1]->str().c_str());
- auto heapType = parseHeapType(*s[2]);
- return Type(Rtt(depth, heapType));
- }
- }
// It's a tuple.
std::vector<Type> types;
for (size_t i = 0; i < s.size(); ++i) {
@@ -2702,24 +2655,12 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
- auto* ref = parseExpression(*s[1]);
- auto* rtt = parseExpression(*s[2]);
- return Builder(wasm).makeRefTest(ref, rtt);
-}
-
Expression* SExpressionWasmBuilder::makeRefTestStatic(Element& s) {
auto heapType = parseHeapType(*s[1]);
auto* ref = parseExpression(*s[2]);
return Builder(wasm).makeRefTest(ref, heapType);
}
-Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
- auto* ref = parseExpression(*s[1]);
- auto* rtt = parseExpression(*s[2]);
- return Builder(wasm).makeRefCast(ref, rtt);
-}
-
Expression* SExpressionWasmBuilder::makeRefCastStatic(Element& s) {
auto heapType = parseHeapType(*s[1]);
auto* ref = parseExpression(*s[2]);
@@ -2735,12 +2676,8 @@ Expression* SExpressionWasmBuilder::makeRefCastNopStatic(Element& s) {
Expression* SExpressionWasmBuilder::makeBrOn(Element& s, BrOnOp op) {
auto name = getLabel(*s[1]);
auto* ref = parseExpression(*s[2]);
- Expression* rtt = nullptr;
- if (op == BrOnCast || op == BrOnCastFail) {
- rtt = parseExpression(*s[3]);
- }
return ValidatingBuilder(wasm, s.line, s.col)
- .validateAndMakeBrOn(op, name, ref, rtt);
+ .validateAndMakeBrOn(op, name, ref);
}
Expression* SExpressionWasmBuilder::makeBrOnStatic(Element& s, BrOnOp op) {
@@ -2750,39 +2687,6 @@ Expression* SExpressionWasmBuilder::makeBrOnStatic(Element& s, BrOnOp op) {
return Builder(wasm).makeBrOn(op, name, ref, heapType);
}
-Expression* SExpressionWasmBuilder::makeRttCanon(Element& s) {
- return Builder(wasm).makeRttCanon(parseHeapType(*s[1]));
-}
-
-Expression* SExpressionWasmBuilder::makeRttSub(Element& s) {
- auto heapType = parseHeapType(*s[1]);
- auto parent = parseExpression(*s[2]);
- return Builder(wasm).makeRttSub(heapType, parent);
-}
-
-Expression* SExpressionWasmBuilder::makeRttFreshSub(Element& s) {
- auto heapType = parseHeapType(*s[1]);
- auto parent = parseExpression(*s[2]);
- return Builder(wasm).makeRttFreshSub(heapType, parent);
-}
-
-Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
- auto heapType = parseHeapType(*s[1]);
- auto numOperands = s.size() - 3;
- if (default_ && numOperands > 0) {
- throw ParseException(
- "arguments provided for struct.new_with_default", s.line, s.col);
- }
- std::vector<Expression*> operands;
- operands.resize(numOperands);
- for (Index i = 0; i < numOperands; i++) {
- operands[i] = parseExpression(*s[i + 2]);
- }
- auto* rtt = parseExpression(*s[s.size() - 1]);
- validateHeapTypeUsingChild(rtt, heapType, s);
- return Builder(wasm).makeStructNew(rtt, operands);
-}
-
Expression* SExpressionWasmBuilder::makeStructNewStatic(Element& s,
bool default_) {
auto heapType = parseHeapType(*s[1]);
@@ -2841,19 +2745,6 @@ Expression* SExpressionWasmBuilder::makeStructSet(Element& s) {
return Builder(wasm).makeStructSet(index, ref, value);
}
-Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) {
- auto heapType = parseHeapType(*s[1]);
- Expression* init = nullptr;
- size_t i = 2;
- if (!default_) {
- init = parseExpression(*s[i++]);
- }
- auto* size = parseExpression(*s[i++]);
- auto* rtt = parseExpression(*s[i++]);
- validateHeapTypeUsingChild(rtt, heapType, s);
- return Builder(wasm).makeArrayNew(rtt, size, init);
-}
-
Expression* SExpressionWasmBuilder::makeArrayNewStatic(Element& s,
bool default_) {
auto heapType = parseHeapType(*s[1]);
@@ -2866,18 +2757,6 @@ Expression* SExpressionWasmBuilder::makeArrayNewStatic(Element& s,
return Builder(wasm).makeArrayNew(heapType, size, init);
}
-Expression* SExpressionWasmBuilder::makeArrayInit(Element& s) {
- auto heapType = parseHeapType(*s[1]);
- size_t i = 2;
- std::vector<Expression*> values;
- while (i < s.size() - 1) {
- values.push_back(parseExpression(*s[i++]));
- }
- auto* rtt = parseExpression(*s[i++]);
- validateHeapTypeUsingChild(rtt, heapType, s);
- return Builder(wasm).makeArrayInit(rtt, values);
-}
-
Expression* SExpressionWasmBuilder::makeArrayInitStatic(Element& s) {
auto heapType = parseHeapType(*s[1]);
size_t i = 2;
@@ -3853,7 +3732,7 @@ void SExpressionWasmBuilder::validateHeapTypeUsingChild(Expression* child,
if (child->type == Type::unreachable) {
return;
}
- if ((!child->type.isRef() && !child->type.isRtt()) ||
+ if (!child->type.isRef() ||
!HeapType::isSubType(child->type.getHeapType(), heapType)) {
throw ParseException("bad heap type: expected " + heapType.toString() +
" but found " + child->type.toString(),
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 2fc06b176..c29384dad 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2016,26 +2016,18 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
void BinaryInstWriter::visitRefTest(RefTest* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- o << U32LEB(BinaryConsts::RefTest);
- } else {
- o << U32LEB(BinaryConsts::RefTestStatic);
- parent.writeIndexedHeapType(curr->intendedType);
- }
+ o << U32LEB(BinaryConsts::RefTestStatic);
+ parent.writeIndexedHeapType(curr->intendedType);
}
void BinaryInstWriter::visitRefCast(RefCast* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- o << U32LEB(BinaryConsts::RefCast);
+ if (curr->safety == RefCast::Unsafe) {
+ o << U32LEB(BinaryConsts::RefCastNopStatic);
} else {
- if (curr->safety == RefCast::Unsafe) {
- o << U32LEB(BinaryConsts::RefCastNopStatic);
- } else {
- o << U32LEB(BinaryConsts::RefCastStatic);
- }
- parent.writeIndexedHeapType(curr->intendedType);
+ o << U32LEB(BinaryConsts::RefCastStatic);
}
+ parent.writeIndexedHeapType(curr->intendedType);
}
void BinaryInstWriter::visitBrOn(BrOn* curr) {
@@ -2048,19 +2040,11 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) {
break;
case BrOnCast:
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- o << U32LEB(BinaryConsts::BrOnCast);
- } else {
- o << U32LEB(BinaryConsts::BrOnCastStatic);
- }
+ o << U32LEB(BinaryConsts::BrOnCastStatic);
break;
case BrOnCastFail:
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- o << U32LEB(BinaryConsts::BrOnCastFail);
- } else {
- o << U32LEB(BinaryConsts::BrOnCastStaticFail);
- }
+ o << U32LEB(BinaryConsts::BrOnCastStaticFail);
break;
case BrOnFunc:
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnFunc);
@@ -2084,36 +2068,17 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) {
WASM_UNREACHABLE("invalid br_on_*");
}
o << U32LEB(getBreakIndex(curr->name));
- if ((curr->op == BrOnCast || curr->op == BrOnCastFail) && !curr->rtt) {
+ if (curr->op == BrOnCast || curr->op == BrOnCastFail) {
parent.writeIndexedHeapType(curr->intendedType);
}
}
-void BinaryInstWriter::visitRttCanon(RttCanon* curr) {
- o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttCanon);
- parent.writeIndexedHeapType(curr->type.getRtt().heapType);
-}
-
-void BinaryInstWriter::visitRttSub(RttSub* curr) {
- o << int8_t(BinaryConsts::GCPrefix);
- o << U32LEB(curr->fresh ? BinaryConsts::RttFreshSub : BinaryConsts::RttSub);
- parent.writeIndexedHeapType(curr->type.getRtt().heapType);
-}
-
void BinaryInstWriter::visitStructNew(StructNew* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::StructNewDefaultWithRtt);
- } else {
- o << U32LEB(BinaryConsts::StructNewWithRtt);
- }
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::StructNewDefault);
} else {
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::StructNewDefault);
- } else {
- o << U32LEB(BinaryConsts::StructNew);
- }
+ o << U32LEB(BinaryConsts::StructNew);
}
parent.writeIndexedHeapType(curr->type.getHeapType());
}
@@ -2142,29 +2107,17 @@ void BinaryInstWriter::visitStructSet(StructSet* curr) {
void BinaryInstWriter::visitArrayNew(ArrayNew* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::ArrayNewDefaultWithRtt);
- } else {
- o << U32LEB(BinaryConsts::ArrayNewWithRtt);
- }
+ if (curr->isWithDefault()) {
+ o << U32LEB(BinaryConsts::ArrayNewDefault);
} else {
- if (curr->isWithDefault()) {
- o << U32LEB(BinaryConsts::ArrayNewDefault);
- } else {
- o << U32LEB(BinaryConsts::ArrayNew);
- }
+ o << U32LEB(BinaryConsts::ArrayNew);
}
parent.writeIndexedHeapType(curr->type.getHeapType());
}
void BinaryInstWriter::visitArrayInit(ArrayInit* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->rtt) {
- o << U32LEB(BinaryConsts::ArrayInit);
- } else {
- o << U32LEB(BinaryConsts::ArrayInitStatic);
- }
+ o << U32LEB(BinaryConsts::ArrayInitStatic);
parent.writeIndexedHeapType(curr->type.getHeapType());
o << U32LEB(curr->values.size());
}
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 84b11000f..23d2877f7 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -60,7 +60,6 @@ struct TypeInfo {
enum Kind {
TupleKind,
RefKind,
- RttKind,
} kind;
struct Ref {
HeapType heapType;
@@ -69,20 +68,17 @@ struct TypeInfo {
union {
Tuple tuple;
Ref ref;
- Rtt rtt;
};
TypeInfo(const Tuple& tuple) : kind(TupleKind), tuple(tuple) {}
TypeInfo(Tuple&& tuple) : kind(TupleKind), tuple(std::move(tuple)) {}
TypeInfo(HeapType heapType, Nullability nullable)
: kind(RefKind), ref{heapType, nullable} {}
- TypeInfo(Rtt rtt) : kind(RttKind), rtt(rtt) {}
TypeInfo(const TypeInfo& other);
~TypeInfo();
constexpr bool isTuple() const { return kind == TupleKind; }
constexpr bool isRef() const { return kind == RefKind; }
- constexpr bool isRtt() const { return kind == RttKind; }
bool isNullable() const { return kind == RefKind && ref.nullable; }
@@ -165,7 +161,6 @@ struct SubTyper {
bool isSubType(const Signature& a, const Signature& b);
bool isSubType(const Struct& a, const Struct& b);
bool isSubType(const Array& a, const Array& b);
- bool isSubType(const Rtt& a, const Rtt& b);
};
// Helper for finding the equirecursive least upper bound of two types.
@@ -192,7 +187,6 @@ private:
std::optional<Signature> lub(const Signature& a, const Signature& b);
Struct lub(const Struct& a, const Struct& b);
std::optional<Array> lub(const Array& a, const Array& b);
- std::optional<Rtt> lub(const Rtt& a, const Rtt& b);
};
// Helper for printing types.
@@ -231,7 +225,6 @@ struct TypePrinter {
std::optional<HeapType> super = std::nullopt);
std::ostream& print(const Array& array,
std::optional<HeapType> super = std::nullopt);
- std::ostream& print(const Rtt& rtt);
};
// Helper for hashing the shapes of TypeInfos and HeapTypeInfos. Keeps track of
@@ -255,7 +248,6 @@ struct FiniteShapeHasher {
size_t hash(const Signature& sig);
size_t hash(const Struct& struct_);
size_t hash(const Array& array);
- size_t hash(const Rtt& rtt);
};
// Helper for comparing the shapes of TypeInfos and HeapTypeInfos for equality.
@@ -281,7 +273,6 @@ struct FiniteShapeEquator {
bool eq(const Signature& a, const Signature& b);
bool eq(const Struct& a, const Struct& b);
bool eq(const Array& a, const Array& b);
- bool eq(const Rtt& a, const Rtt& b);
};
struct RecGroupHasher {
@@ -307,7 +298,6 @@ struct RecGroupHasher {
size_t hash(const Signature& sig) const;
size_t hash(const Struct& struct_) const;
size_t hash(const Array& array) const;
- size_t hash(const Rtt& rtt) const;
};
struct RecGroupEquator {
@@ -334,7 +324,6 @@ struct RecGroupEquator {
bool eq(const Signature& a, const Signature& b) const;
bool eq(const Struct& a, const Struct& b) const;
bool eq(const Array& a, const Array& b) const;
- bool eq(const Rtt& a, const Rtt& b) const;
};
// A wrapper around a RecGroup that provides equality and hashing based on the
@@ -626,9 +615,6 @@ TypeInfo::TypeInfo(const TypeInfo& other) {
case RefKind:
new (&ref) auto(other.ref);
return;
- case RttKind:
- new (&rtt) auto(other.rtt);
- return;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -641,9 +627,6 @@ TypeInfo::~TypeInfo() {
case RefKind:
ref.~Ref();
return;
- case RttKind:
- rtt.~Rtt();
- return;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -670,8 +653,6 @@ bool TypeInfo::operator==(const TypeInfo& other) const {
case RefKind:
return ref.nullable == other.ref.nullable &&
ref.heapType == other.ref.heapType;
- case RttKind:
- return rtt == other.rtt;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -947,11 +928,6 @@ Type::Type(HeapType heapType, Nullability nullable) {
new (this) Type(globalTypeStore.insert(TypeInfo(heapType, nullable)));
}
-Type::Type(Rtt rtt) {
- assert(!isTemp(rtt.heapType) && "Leaking temporary type!");
- new (this) Type(globalTypeStore.insert(rtt));
-}
-
bool Type::isTuple() const {
if (isBasic()) {
return false;
@@ -1002,14 +978,6 @@ bool Type::isNonNullable() const {
}
}
-bool Type::isRtt() const {
- if (isBasic()) {
- return false;
- } else {
- return getTypeInfo(*this)->isRtt();
- }
-}
-
bool Type::isStruct() const { return isRef() && getHeapType().isStruct(); }
bool Type::isArray() const { return isRef() && getHeapType().isArray(); }
@@ -1026,19 +994,7 @@ bool Type::isDefaultable() const {
}
return true;
}
- return isConcrete() && !isNonNullable() && !isRtt();
-}
-
-bool Type::isDefaultableOrNonNullable() const {
- if (isTuple()) {
- for (auto t : *this) {
- if (!t.isDefaultableOrNonNullable()) {
- return false;
- }
- }
- return true;
- }
- return isConcrete() && !isRtt();
+ return isConcrete() && !isNonNullable();
}
Nullability Type::getNullability() const {
@@ -1132,8 +1088,6 @@ FeatureSet Type::getFeatures() const {
// load of the wasm we don't know the features yet, so we apply the more
// refined types), so we don't add that in any case here.
return FeatureSet::ReferenceTypes;
- } else if (t.isRtt()) {
- return FeatureSet::ReferenceTypes | FeatureSet::GC;
}
TODO_SINGLE_COMPOUND(t);
switch (t.getBasic()) {
@@ -1179,18 +1133,11 @@ HeapType Type::getHeapType() const {
break;
case TypeInfo::RefKind:
return info->ref.heapType;
- case TypeInfo::RttKind:
- return info->rtt.heapType;
}
WASM_UNREACHABLE("Unexpected type");
}
}
-Rtt Type::getRtt() const {
- assert(isRtt());
- return getTypeInfo(*this)->rtt;
-}
-
Type Type::get(unsigned byteSize, bool float_) {
if (byteSize < 4) {
return Type::i32;
@@ -1264,15 +1211,6 @@ Type Type::getLeastUpperBound(Type a, Type b) {
HeapType::getLeastUpperBound(a.getHeapType(), b.getHeapType());
return Type(heapType, nullability);
}
- if (a.isRtt() && b.isRtt()) {
- auto heapType = a.getHeapType();
- if (heapType != b.getHeapType()) {
- return Type::none;
- }
- auto rttA = a.getRtt(), rttB = b.getRtt();
- auto depth = rttA.depth == rttB.depth ? rttA.depth : Rtt::NoDepth;
- return Rtt(depth, heapType);
- }
return Type::none;
WASM_UNREACHABLE("unexpected type");
}
@@ -1593,7 +1531,6 @@ std::string Tuple::toString() const { return genericToString(*this); }
std::string Signature::toString() const { return genericToString(*this); }
std::string Struct::toString() const { return genericToString(*this); }
std::string Array::toString() const { return genericToString(*this); }
-std::string Rtt::toString() const { return genericToString(*this); }
std::ostream& operator<<(std::ostream& os, Type type) {
return TypePrinter(os).print(type);
@@ -1622,9 +1559,6 @@ std::ostream& operator<<(std::ostream& os, Struct struct_) {
std::ostream& operator<<(std::ostream& os, Array array) {
return TypePrinter(os).print(array);
}
-std::ostream& operator<<(std::ostream& os, Rtt rtt) {
- return TypePrinter(os).print(rtt);
-}
std::ostream& operator<<(std::ostream& os, TypeBuilder::ErrorReason reason) {
switch (reason) {
case TypeBuilder::ErrorReason::SelfSupertype:
@@ -1670,9 +1604,6 @@ bool SubTyper::isSubType(Type a, Type b) {
if (a.isTuple() && b.isTuple()) {
return isSubType(a.getTuple(), b.getTuple());
}
- if (a.isRtt() && b.isRtt()) {
- return isSubType(a.getRtt(), b.getRtt());
- }
return false;
}
@@ -1783,13 +1714,6 @@ bool SubTyper::isSubType(const Array& a, const Array& b) {
return isSubType(a.element, b.element);
}
-bool SubTyper::isSubType(const Rtt& a, const Rtt& b) {
- // (rtt n $x) is a subtype of (rtt $x), that is, if the only difference in
- // information is that the left side specifies a depth while the right side
- // allows any depth.
- return a.heapType == b.heapType && a.hasDepth() && !b.hasDepth();
-}
-
bool TypeBounder::hasLeastUpperBound(Type a, Type b) { return bool(lub(a, b)); }
Type TypeBounder::getLeastUpperBound(Type a, Type b) {
@@ -1847,12 +1771,6 @@ std::optional<Type> TypeBounder::lub(Type a, Type b) {
(a.isNullable() || b.isNullable()) ? Nullable : NonNullable;
HeapType heapType = lub(a.getHeapType(), b.getHeapType());
return builder.getTempRefType(heapType, nullability);
- } else if (a.isRtt() && b.isRtt()) {
- auto rtt = lub(a.getRtt(), b.getRtt());
- if (!rtt) {
- return {};
- }
- return builder.getTempRttType(*rtt);
}
return {};
}
@@ -1987,14 +1905,6 @@ std::optional<Array> TypeBounder::lub(const Array& a, const Array& b) {
}
}
-std::optional<Rtt> TypeBounder::lub(const Rtt& a, const Rtt& b) {
- if (a.heapType != b.heapType) {
- return {};
- }
- uint32_t depth = (a.depth == b.depth) ? a.depth : Rtt::NoDepth;
- return Rtt(depth, a.heapType);
-}
-
void TypePrinter::printHeapTypeName(HeapType type) {
if (type.isBasic()) {
print(type);
@@ -2080,8 +1990,6 @@ std::ostream& TypePrinter::print(Type type) {
}
printHeapTypeName(heapType);
os << ')';
- } else if (type.isRtt()) {
- print(type.getRtt());
} else {
WASM_UNREACHABLE("unexpected type");
}
@@ -2234,15 +2142,6 @@ std::ostream& TypePrinter::print(const Array& array,
return os << ')';
}
-std::ostream& TypePrinter::print(const Rtt& rtt) {
- os << "(rtt ";
- if (rtt.hasDepth()) {
- os << rtt.depth << ' ';
- }
- printHeapTypeName(rtt.heapType);
- return os << ')';
-}
-
size_t FiniteShapeHasher::hash(Type type) {
size_t digest = wasm::hash(type.isBasic());
if (type.isBasic()) {
@@ -2285,9 +2184,6 @@ size_t FiniteShapeHasher::hash(const TypeInfo& info) {
rehash(digest, info.ref.nullable);
hash_combine(digest, hash(info.ref.heapType));
return digest;
- case TypeInfo::RttKind:
- hash_combine(digest, hash(info.rtt));
- return digest;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -2355,12 +2251,6 @@ size_t FiniteShapeHasher::hash(const Array& array) {
return hash(array.element);
}
-size_t FiniteShapeHasher::hash(const Rtt& rtt) {
- size_t digest = wasm::hash(rtt.depth);
- hash_combine(digest, hash(rtt.heapType));
- return digest;
-}
-
bool FiniteShapeEquator::eq(Type a, Type b) {
if (a.isBasic() != b.isBasic()) {
return false;
@@ -2404,8 +2294,6 @@ bool FiniteShapeEquator::eq(const TypeInfo& a, const TypeInfo& b) {
case TypeInfo::RefKind:
return a.ref.nullable == b.ref.nullable &&
eq(a.ref.heapType, b.ref.heapType);
- case TypeInfo::RttKind:
- return eq(a.rtt, b.rtt);
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -2466,10 +2354,6 @@ bool FiniteShapeEquator::eq(const Array& a, const Array& b) {
return eq(a.element, b.element);
}
-bool FiniteShapeEquator::eq(const Rtt& a, const Rtt& b) {
- return a.depth == b.depth && eq(a.heapType, b.heapType);
-}
-
size_t RecGroupHasher::operator()() const {
size_t digest = wasm::hash(group.size());
for (auto type : group) {
@@ -2526,9 +2410,6 @@ size_t RecGroupHasher::hash(const TypeInfo& info) const {
rehash(digest, info.ref.nullable);
hash_combine(digest, hash(info.ref.heapType));
return digest;
- case TypeInfo::RttKind:
- hash_combine(digest, hash(info.rtt));
- return digest;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -2589,12 +2470,6 @@ size_t RecGroupHasher::hash(const Array& array) const {
return hash(array.element);
}
-size_t RecGroupHasher::hash(const Rtt& rtt) const {
- size_t digest = wasm::hash(rtt.depth);
- hash_combine(digest, hash(rtt.heapType));
- return digest;
-}
-
bool RecGroupEquator::operator()() const {
if (newGroup == otherGroup) {
return true;
@@ -2655,8 +2530,6 @@ bool RecGroupEquator::eq(const TypeInfo& a, const TypeInfo& b) const {
case TypeInfo::RefKind:
return a.ref.nullable == b.ref.nullable &&
eq(a.ref.heapType, b.ref.heapType);
- case TypeInfo::RttKind:
- return eq(a.rtt, b.rtt);
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -2717,10 +2590,6 @@ bool RecGroupEquator::eq(const Array& a, const Array& b) const {
return eq(a.element, b.element);
}
-bool RecGroupEquator::eq(const Rtt& a, const Rtt& b) const {
- return a.depth == b.depth && eq(a.heapType, b.heapType);
-}
-
template<typename Self> void TypeGraphWalkerBase<Self>::walkRoot(Type* type) {
assert(taskList.empty());
taskList.push_back(Task::scan(type));
@@ -2781,9 +2650,6 @@ template<typename Self> void TypeGraphWalkerBase<Self>::scanType(Type* type) {
taskList.push_back(Task::scan(&info->ref.heapType));
break;
}
- case TypeInfo::RttKind:
- taskList.push_back(Task::scan(&info->rtt.heapType));
- break;
}
}
@@ -2921,10 +2787,6 @@ Type TypeBuilder::getTempRefType(HeapType type, Nullability nullable) {
return markTemp(impl->typeStore.insert(TypeInfo(type, nullable)));
}
-Type TypeBuilder::getTempRttType(Rtt rtt) {
- return markTemp(impl->typeStore.insert(rtt));
-}
-
void TypeBuilder::setSubType(size_t i, size_t j) {
assert(i < size() && j < size() && "index out of bounds");
HeapTypeInfo* sub = impl->entries[i].info.get();
@@ -4031,12 +3893,6 @@ size_t hash<wasm::RecGroup>::operator()(const wasm::RecGroup& group) const {
return wasm::hash(group.getID());
}
-size_t hash<wasm::Rtt>::operator()(const wasm::Rtt& rtt) const {
- auto digest = wasm::hash(rtt.depth);
- wasm::rehash(digest, rtt.heapType);
- return digest;
-}
-
size_t hash<wasm::TypeInfo>::operator()(const wasm::TypeInfo& info) const {
auto digest = wasm::hash(info.kind);
switch (info.kind) {
@@ -4047,9 +3903,6 @@ size_t hash<wasm::TypeInfo>::operator()(const wasm::TypeInfo& info) const {
wasm::rehash(digest, info.ref.nullable);
wasm::rehash(digest, info.ref.heapType);
return digest;
- case wasm::TypeInfo::RttKind:
- wasm::rehash(digest, info.rtt);
- return digest;
}
WASM_UNREACHABLE("unexpected kind");
}
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 65a910747..bc51d8b63 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -383,8 +383,6 @@ public:
void visitRefTest(RefTest* curr);
void visitRefCast(RefCast* curr);
void visitBrOn(BrOn* curr);
- void visitRttCanon(RttCanon* curr);
- void visitRttSub(RttSub* curr);
void visitStructNew(StructNew* curr);
void visitStructGet(StructGet* curr);
void visitStructSet(StructSet* curr);
@@ -2338,23 +2336,12 @@ void FunctionValidator::visitRefTest(RefTest* curr) {
shouldBeTrue(
curr->ref->type.isRef(), curr, "ref.test ref must have ref type");
}
- if (curr->rtt) {
- if (curr->rtt->type != Type::unreachable) {
- shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type");
- }
- shouldBeEqual(curr->intendedType,
+ shouldBeUnequal(curr->intendedType,
HeapType(),
curr,
- "dynamic ref.test must not use intendedType field");
- } else {
- shouldBeUnequal(curr->intendedType,
- HeapType(),
- curr,
- "static ref.test must set intendedType field");
- shouldBeTrue(
- !curr->intendedType.isBasic(), curr, "ref.test must test a non-basic");
- }
+ "static ref.test must set intendedType field");
+ shouldBeTrue(
+ !curr->intendedType.isBasic(), curr, "ref.test must test a non-basic");
}
void FunctionValidator::visitRefCast(RefCast* curr) {
@@ -2364,23 +2351,12 @@ void FunctionValidator::visitRefCast(RefCast* curr) {
shouldBeTrue(
curr->ref->type.isRef(), curr, "ref.cast ref must have ref type");
}
- if (curr->rtt) {
- if (curr->rtt->type != Type::unreachable) {
- shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "ref.cast rtt must have rtt type");
- }
- shouldBeEqual(curr->intendedType,
+ shouldBeUnequal(curr->intendedType,
HeapType(),
curr,
- "dynamic ref.cast must not use intendedType field");
- } else {
- shouldBeUnequal(curr->intendedType,
- HeapType(),
- curr,
- "static ref.cast must set intendedType field");
- shouldBeTrue(
- !curr->intendedType.isBasic(), curr, "ref.cast must cast to a non-basic");
- }
+ "static ref.cast must set intendedType field");
+ shouldBeTrue(
+ !curr->intendedType.isBasic(), curr, "ref.cast must cast to a non-basic");
}
void FunctionValidator::visitBrOn(BrOn* curr) {
@@ -2392,28 +2368,14 @@ void FunctionValidator::visitBrOn(BrOn* curr) {
curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type");
}
if (curr->op == BrOnCast || curr->op == BrOnCastFail) {
- if (curr->rtt) {
- // Note that an unreachable rtt is not supported: the text and binary
- // formats do not provide the type, so if it's unreachable we should not
- // even create a br_on_cast in such a case, as we'd have no idea what it
- // casts to.
- shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "br_on_cast rtt must have rtt type");
- shouldBeEqual(curr->intendedType,
+ shouldBeUnequal(curr->intendedType,
HeapType(),
curr,
- "dynamic br_on_cast* must not use intendedType field");
- } else {
- shouldBeUnequal(curr->intendedType,
- HeapType(),
- curr,
- "static br_on_cast* must set intendedType field");
- shouldBeTrue(!curr->intendedType.isBasic(),
- curr,
- "br_on_cast* must cast to a non-basic");
- }
+ "static br_on_cast* must set intendedType field");
+ shouldBeTrue(!curr->intendedType.isBasic(),
+ curr,
+ "br_on_cast* must cast to a non-basic");
} else {
- shouldBeTrue(curr->rtt == nullptr, curr, "non-cast BrOn must not have rtt");
shouldBeEqual(curr->intendedType,
HeapType(),
curr,
@@ -2422,38 +2384,6 @@ void FunctionValidator::visitBrOn(BrOn* curr) {
noteBreak(curr->name, curr->getSentType(), curr);
}
-void FunctionValidator::visitRttCanon(RttCanon* curr) {
- shouldBeTrue(
- getModule()->features.hasGC(), curr, "rtt.canon requires gc to be enabled");
- shouldBeTrue(curr->type.isRtt(), curr, "rtt.canon must have RTT type");
- auto rtt = curr->type.getRtt();
- shouldBeEqual(rtt.depth,
- Index(curr->type.getHeapType().getDepth()),
- curr,
- "rtt.canon must have the depth of its heap type");
-}
-
-void FunctionValidator::visitRttSub(RttSub* curr) {
- shouldBeTrue(
- getModule()->features.hasGC(), curr, "rtt.sub requires gc to be enabled");
- shouldBeTrue(curr->type.isRtt(), curr, "rtt.sub must have RTT type");
- if (curr->parent->type != Type::unreachable) {
- shouldBeTrue(
- curr->parent->type.isRtt(), curr, "rtt.sub parent must have RTT type");
- auto parentRtt = curr->parent->type.getRtt();
- auto rtt = curr->type.getRtt();
- if (rtt.hasDepth() && parentRtt.hasDepth()) {
- shouldBeEqual(rtt.depth,
- parentRtt.depth + 1,
- curr,
- "rtt.canon has a depth of 1 over the parent");
- }
- shouldBeTrue(HeapType::isSubType(rtt.heapType, parentRtt.heapType),
- curr,
- "rtt.sub parent must be a supertype");
- }
-}
-
void FunctionValidator::visitStructNew(StructNew* curr) {
shouldBeTrue(getModule()->features.hasGC(),
curr,
@@ -2461,19 +2391,7 @@ void FunctionValidator::visitStructNew(StructNew* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (curr->rtt) {
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "struct.new rtt must be rtt")) {
- return;
- }
- }
auto heapType = curr->type.getHeapType();
- if (curr->rtt) {
- shouldBeEqual(curr->rtt->type.getHeapType(),
- heapType,
- curr,
- "struct.new heap type must match rtt");
- }
if (!shouldBeTrue(
heapType.isStruct(), curr, "struct.new heap type must be struct")) {
return;
@@ -2565,19 +2483,7 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (curr->rtt) {
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "array.new rtt must be rtt")) {
- return;
- }
- }
auto heapType = curr->type.getHeapType();
- if (curr->rtt) {
- shouldBeEqual(curr->rtt->type.getHeapType(),
- heapType,
- curr,
- "array.new heap type must match rtt");
- }
if (!shouldBeTrue(
heapType.isArray(), curr, "array.new heap type must be array")) {
return;
@@ -2607,19 +2513,7 @@ void FunctionValidator::visitArrayInit(ArrayInit* curr) {
if (curr->type == Type::unreachable) {
return;
}
- if (curr->rtt) {
- if (!shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "array.init rtt must be rtt")) {
- return;
- }
- }
auto heapType = curr->type.getHeapType();
- if (curr->rtt) {
- shouldBeEqual(curr->rtt->type.getHeapType(),
- heapType,
- curr,
- "array.init heap type must match rtt");
- }
if (!shouldBeTrue(
heapType.isArray(), curr, "array.init heap type must be array")) {
return;
@@ -2716,9 +2610,7 @@ void FunctionValidator::visitFunction(Function* curr) {
}
for (const auto& var : curr->vars) {
features |= var.getFeatures();
- bool valid = getModule()->features.hasGCNNLocals()
- ? var.isDefaultableOrNonNullable()
- : var.isDefaultable();
+ bool valid = getModule()->features.hasGCNNLocals() || var.isDefaultable();
shouldBeTrue(valid, var, "vars must be defaultable");
}
shouldBeTrue(features <= getModule()->features,
@@ -3167,10 +3059,9 @@ static void validateTables(Module& module, ValidationInfo& info) {
for (auto& segment : module.elementSegments) {
// Since element segment items need to be constant expressions, that leaves
- // us with ref.null, ref.func and global.get. The GC proposal adds rtt.canon
- // and rtt.sub to the list, but Binaryen doesn't consider RTTs as reference-
- // types yet. As a result, the only possible type for element segments will
- // be function references.
+ // us with ref.null, ref.func and global.get. As a result, the only possible
+ // type for element segments will be function references.
+ // TODO: This is not true! Allow GC data here (#4846).
info.shouldBeTrue(segment->type.isFunction(),
"elem",
"element segment type must be of function type.");
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 1a6acf5bd..34b1e82b7 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -931,36 +931,25 @@ void CallRef::finalize(Type type_) {
}
void RefTest::finalize() {
- if (ref->type == Type::unreachable ||
- (rtt && rtt->type == Type::unreachable)) {
+ if (ref->type == Type::unreachable) {
type = Type::unreachable;
} else {
type = Type::i32;
}
}
-HeapType RefTest::getIntendedType() {
- return rtt ? rtt->type.getHeapType() : intendedType;
-}
-
void RefCast::finalize() {
- if (ref->type == Type::unreachable ||
- (rtt && rtt->type == Type::unreachable)) {
+ if (ref->type == Type::unreachable) {
type = Type::unreachable;
} else {
// The output of ref.cast may be null if the input is null (in that case the
// null is passed through).
- type = Type(getIntendedType(), ref->type.getNullability());
+ type = Type(intendedType, ref->type.getNullability());
}
}
-HeapType RefCast::getIntendedType() {
- return rtt ? rtt->type.getHeapType() : intendedType;
-}
-
void BrOn::finalize() {
- if (ref->type == Type::unreachable ||
- (rtt && rtt->type == Type::unreachable)) {
+ if (ref->type == Type::unreachable) {
type = Type::unreachable;
return;
}
@@ -984,7 +973,7 @@ void BrOn::finalize() {
case BrOnCastFail:
// If we do not branch, the cast worked, and we have something of the cast
// type.
- type = Type(getIntendedType(), NonNullable);
+ type = Type(intendedType, NonNullable);
break;
case BrOnNonFunc:
type = Type(HeapType::func, NonNullable);
@@ -1000,11 +989,6 @@ void BrOn::finalize() {
}
}
-HeapType BrOn::getIntendedType() {
- assert(op == BrOnCast || op == BrOnCastFail);
- return rtt ? rtt->type.getHeapType() : intendedType;
-}
-
Type BrOn::getSentType() {
switch (op) {
case BrOnNull:
@@ -1022,7 +1006,7 @@ Type BrOn::getSentType() {
if (ref->type == Type::unreachable) {
return Type::unreachable;
}
- return Type(getIntendedType(), NonNullable);
+ return Type(intendedType, NonNullable);
case BrOnFunc:
return Type(HeapType::func, NonNullable);
case BrOnData:
@@ -1039,31 +1023,10 @@ Type BrOn::getSentType() {
}
}
-void RttCanon::finalize() {
- // Nothing to do - the type must have been set already during construction.
-}
-
-void RttSub::finalize() {
- if (parent->type == Type::unreachable) {
- type = Type::unreachable;
- }
- // Else nothing to do - the type must have been set already during
- // construction.
-}
-
void StructNew::finalize() {
- if (rtt && rtt->type == Type::unreachable) {
- type = Type::unreachable;
- return;
- }
if (handleUnreachableOperands(this)) {
return;
}
- // A dynamic StructNew infers the type from the rtt. A static one has the type
- // already in the type field.
- if (rtt) {
- type = Type(rtt->type.getHeapType(), NonNullable);
- }
}
void StructGet::finalize() {
@@ -1083,35 +1046,20 @@ void StructSet::finalize() {
}
void ArrayNew::finalize() {
- if ((rtt && rtt->type == Type::unreachable) ||
- size->type == Type::unreachable ||
+ if (size->type == Type::unreachable ||
(init && init->type == Type::unreachable)) {
type = Type::unreachable;
return;
}
- // A dynamic ArrayNew infers the type from the rtt. A static one has the type
- // already in the type field.
- if (rtt) {
- type = Type(rtt->type.getHeapType(), NonNullable);
- }
}
void ArrayInit::finalize() {
- if (rtt && rtt->type == Type::unreachable) {
- type = Type::unreachable;
- return;
- }
for (auto* value : values) {
if (value->type == Type::unreachable) {
type = Type::unreachable;
return;
}
}
- // A dynamic ArrayInit infers the type from the rtt. A static one has the type
- // already in the type field.
- if (rtt) {
- type = Type(rtt->type.getHeapType(), NonNullable);
- }
}
void ArrayGet::finalize() {
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index 8b86017ff..89eab3297 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -967,14 +967,6 @@ Result<typename Ctx::InstrT> makeBrOn(Ctx&, ParseInput&, BrOnOp op);
template<typename Ctx>
Result<typename Ctx::InstrT> makeBrOnStatic(Ctx&, ParseInput&, BrOnOp op);
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttCanon(Ctx&, ParseInput&);
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttSub(Ctx&, ParseInput&);
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttFreshSub(Ctx&, ParseInput&);
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeStructNew(Ctx&, ParseInput&, bool default_);
-template<typename Ctx>
Result<typename Ctx::InstrT>
makeStructNewStatic(Ctx&, ParseInput&, bool default_);
template<typename Ctx>
@@ -983,13 +975,9 @@ makeStructGet(Ctx&, ParseInput&, bool signed_ = false);
template<typename Ctx>
Result<typename Ctx::InstrT> makeStructSet(Ctx&, ParseInput&);
template<typename Ctx>
-Result<typename Ctx::InstrT> makeArrayNew(Ctx&, ParseInput&, bool default_);
-template<typename Ctx>
Result<typename Ctx::InstrT>
makeArrayNewStatic(Ctx&, ParseInput&, bool default_);
template<typename Ctx>
-Result<typename Ctx::InstrT> makeArrayInit(Ctx&, ParseInput&);
-template<typename Ctx>
Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx&, ParseInput&);
template<typename Ctx>
Result<typename Ctx::InstrT>
@@ -1779,27 +1767,6 @@ makeBrOnStatic(Ctx& ctx, ParseInput& in, BrOnOp op) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttCanon(Ctx& ctx, ParseInput& in) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttSub(Ctx& ctx, ParseInput& in) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRttFreshSub(Ctx& ctx, ParseInput& in) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeStructNew(Ctx& ctx, ParseInput& in, bool default_) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
Result<typename Ctx::InstrT>
makeStructNewStatic(Ctx& ctx, ParseInput& in, bool default_) {
return in.err("unimplemented instruction");
@@ -1818,22 +1785,11 @@ Result<typename Ctx::InstrT> makeStructSet(Ctx& ctx, ParseInput& in) {
template<typename Ctx>
Result<typename Ctx::InstrT>
-makeArrayNew(Ctx& ctx, ParseInput& in, bool default_) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
-Result<typename Ctx::InstrT>
makeArrayNewStatic(Ctx& ctx, ParseInput& in, bool default_) {
return in.err("unimplemented instruction");
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeArrayInit(Ctx& ctx, ParseInput& in) {
- return in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx& ctx, ParseInput& in) {
return in.err("unimplemented instruction");
}
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 034f9a215..442fd0d6e 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -2259,14 +2259,6 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
- Ref visitRttCanon(RttCanon* curr) {
- unimplemented(curr);
- WASM_UNREACHABLE("unimp");
- }
- Ref visitRttSub(RttSub* curr) {
- unimplemented(curr);
- WASM_UNREACHABLE("unimp");
- }
Ref visitStructNew(StructNew* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");