summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp3
-rw-r--r--src/gen-s-parser.inc342
-rw-r--r--src/ir/stack-utils.h6
-rw-r--r--src/passes/OptimizeCasts.cpp6
-rw-r--r--src/passes/OptimizeInstructions.cpp14
-rw-r--r--src/passes/Print.cpp10
-rw-r--r--src/passes/RemoveUnusedBrs.cpp3
-rw-r--r--src/tools/fuzzing/fuzzing.cpp3
-rw-r--r--src/wasm-binary.h18
-rw-r--r--src/wasm-builder.h5
-rw-r--r--src/wasm-delegations-fields.def1
-rw-r--r--src/wasm-s-parser.h10
-rw-r--r--src/wasm.h5
-rw-r--r--src/wasm/wasm-binary.cpp147
-rw-r--r--src/wasm/wasm-s-parser.cpp68
-rw-r--r--src/wasm/wasm-stack.cpp13
-rw-r--r--src/wasm/wat-parser.cpp26
17 files changed, 130 insertions, 550 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index dd2ad5c4a..0b7adf92a 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1768,8 +1768,7 @@ BinaryenExpressionRef BinaryenRefCast(BinaryenModuleRef module,
BinaryenExpressionRef ref,
BinaryenType type) {
return static_cast<Expression*>(
- Builder(*(Module*)module)
- .makeRefCast((Expression*)ref, Type(type), RefCast::Safety::Safe));
+ Builder(*(Module*)module).makeRefCast((Expression*)ref, Type(type)));
}
BinaryenExpressionRef BinaryenBrOn(BinaryenModuleRef module,
BinaryenOp op,
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 772847f9b..ce7baadd5 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -117,52 +117,19 @@ switch (buf[0]) {
case 'c': {
switch (buf[10]) {
case '\0':
- if (op == "br_on_cast"sv) { return makeBrOnCast(s, std::nullopt); }
+ if (op == "br_on_cast"sv) { return makeBrOnCast(s); }
+ goto parse_error;
+ case '_':
+ if (op == "br_on_cast_fail"sv) { return makeBrOnCast(s, true); }
goto parse_error;
- case '_': {
- switch (buf[11]) {
- case 'f':
- if (op == "br_on_cast_fail"sv) { return makeBrOnCast(s, std::nullopt, true); }
- goto parse_error;
- case 's': {
- switch (buf[17]) {
- case '\0':
- if (op == "br_on_cast_static"sv) { return makeBrOnCast(s, std::nullopt); }
- goto parse_error;
- case '_':
- if (op == "br_on_cast_static_fail"sv) { return makeBrOnCast(s, std::nullopt, true); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
- }
- }
default: goto parse_error;
}
}
- case 'f':
- if (op == "br_on_func"sv) { return makeBrOnCast(s, Type(HeapType::func, NonNullable)); }
- goto parse_error;
- case 'i':
- if (op == "br_on_i31"sv) { return makeBrOnCast(s, Type(HeapType::i31, NonNullable)); }
- goto parse_error;
case 'n': {
switch (buf[7]) {
- case 'o': {
- switch (buf[10]) {
- case 'f':
- if (op == "br_on_non_func"sv) { return makeBrOnCast(s, Type(HeapType::func, NonNullable), true); }
- goto parse_error;
- case 'i':
- if (op == "br_on_non_i31"sv) { return makeBrOnCast(s, Type(HeapType::i31, NonNullable), true); }
- goto parse_error;
- case 'n':
- if (op == "br_on_non_null"sv) { return makeBrOnNull(s, true); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case 'o':
+ if (op == "br_on_non_null"sv) { return makeBrOnNull(s, true); }
+ goto parse_error;
case 'u':
if (op == "br_on_null"sv) { return makeBrOnNull(s); }
goto parse_error;
@@ -3008,81 +2975,27 @@ switch (buf[0]) {
switch (buf[2]) {
case 'f': {
switch (buf[4]) {
- case 'a': {
- switch (buf[7]) {
- case 'f':
- if (op == "ref.as_func"sv) { return makeRefCast(s, Type(HeapType::func, NonNullable)); }
- goto parse_error;
- case 'i':
- if (op == "ref.as_i31"sv) { return makeRefCast(s, Type(HeapType::i31, NonNullable)); }
- goto parse_error;
- case 'n':
- if (op == "ref.as_non_null"sv) { return makeRefAs(s, RefAsNonNull); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'c': {
- switch (buf[8]) {
- case '\0':
- if (op == "ref.cast"sv) { return makeRefCast(s); }
- goto parse_error;
- case '_': {
- switch (buf[9]) {
- case 'n': {
- switch (buf[12]) {
- case '\0':
- if (op == "ref.cast_nop"sv) { return makeRefCastNop(s); }
- goto parse_error;
- case '_':
- if (op == "ref.cast_nop_static"sv) { return makeRefCastNop(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 's':
- if (op == "ref.cast_static"sv) { return makeRefCast(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
- }
- }
+ case 'a':
+ if (op == "ref.as_non_null"sv) { return makeRefAs(s, RefAsNonNull); }
+ goto parse_error;
+ case 'c':
+ if (op == "ref.cast"sv) { return makeRefCast(s); }
+ goto parse_error;
case 'e':
if (op == "ref.eq"sv) { return makeRefEq(s); }
goto parse_error;
case 'f':
if (op == "ref.func"sv) { return makeRefFunc(s); }
goto parse_error;
- case 'i': {
- switch (buf[7]) {
- case 'f':
- if (op == "ref.is_func"sv) { return makeRefTest(s, Type(HeapType::func, NonNullable)); }
- goto parse_error;
- case 'i':
- if (op == "ref.is_i31"sv) { return makeRefTest(s, Type(HeapType::i31, NonNullable)); }
- goto parse_error;
- case 'n':
- if (op == "ref.is_null"sv) { return makeRefIsNull(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case 'i':
+ if (op == "ref.is_null"sv) { return makeRefIsNull(s); }
+ goto parse_error;
case 'n':
if (op == "ref.null"sv) { return makeRefNull(s); }
goto parse_error;
- case 't': {
- switch (buf[8]) {
- case '\0':
- if (op == "ref.test"sv) { return makeRefTest(s); }
- goto parse_error;
- case '_':
- if (op == "ref.test_static"sv) { return makeRefTest(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
+ case 't':
+ if (op == "ref.test"sv) { return makeRefTest(s); }
+ goto parse_error;
default: goto parse_error;
}
}
@@ -3795,87 +3708,30 @@ switch (buf[0]) {
switch (buf[10]) {
case '\0':
if (op == "br_on_cast"sv) {
- auto ret = makeBrOnCast(ctx, pos, std::nullopt);
+ auto ret = makeBrOnCast(ctx, pos);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case '_': {
- switch (buf[11]) {
- case 'f':
- if (op == "br_on_cast_fail"sv) {
- auto ret = makeBrOnCast(ctx, pos, std::nullopt, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 's': {
- switch (buf[17]) {
- case '\0':
- if (op == "br_on_cast_static"sv) {
- auto ret = makeBrOnCast(ctx, pos, std::nullopt);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "br_on_cast_static_fail"sv) {
- auto ret = makeBrOnCast(ctx, pos, std::nullopt, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
+ case '_':
+ if (op == "br_on_cast_fail"sv) {
+ auto ret = makeBrOnCast(ctx, pos, true);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
default: goto parse_error;
}
}
- case 'f':
- if (op == "br_on_func"sv) {
- auto ret = makeBrOnCast(ctx, pos, Type(HeapType::func, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "br_on_i31"sv) {
- auto ret = makeBrOnCast(ctx, pos, Type(HeapType::i31, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
case 'n': {
switch (buf[7]) {
- case 'o': {
- switch (buf[10]) {
- case 'f':
- if (op == "br_on_non_func"sv) {
- auto ret = makeBrOnCast(ctx, pos, Type(HeapType::func, NonNullable), true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "br_on_non_i31"sv) {
- auto ret = makeBrOnCast(ctx, pos, Type(HeapType::i31, NonNullable), true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'n':
- if (op == "br_on_non_null"sv) {
- auto ret = makeBrOnNull(ctx, pos, true);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'o':
+ if (op == "br_on_non_null"sv) {
+ auto ret = makeBrOnNull(ctx, pos, true);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
case 'u':
if (op == "br_on_null"sv) {
auto ret = makeBrOnNull(ctx, pos);
@@ -8649,75 +8505,20 @@ switch (buf[0]) {
switch (buf[2]) {
case 'f': {
switch (buf[4]) {
- case 'a': {
- switch (buf[7]) {
- case 'f':
- if (op == "ref.as_func"sv) {
- auto ret = makeRefCast(ctx, pos, Type(HeapType::func, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "ref.as_i31"sv) {
- auto ret = makeRefCast(ctx, pos, Type(HeapType::i31, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'n':
- if (op == "ref.as_non_null"sv) {
- auto ret = makeRefAs(ctx, pos, RefAsNonNull);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'a':
+ if (op == "ref.as_non_null"sv) {
+ auto ret = makeRefAs(ctx, pos, RefAsNonNull);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
- case 'c': {
- switch (buf[8]) {
- case '\0':
- if (op == "ref.cast"sv) {
- auto ret = makeRefCast(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_': {
- switch (buf[9]) {
- case 'n': {
- switch (buf[12]) {
- case '\0':
- if (op == "ref.cast_nop"sv) {
- auto ret = makeRefCastNop(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "ref.cast_nop_static"sv) {
- auto ret = makeRefCastNop(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 's':
- if (op == "ref.cast_static"sv) {
- auto ret = makeRefCast(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- default: goto parse_error;
+ goto parse_error;
+ case 'c':
+ if (op == "ref.cast"sv) {
+ auto ret = makeRefCast(ctx, pos);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
case 'e':
if (op == "ref.eq"sv) {
auto ret = makeRefEq(ctx, pos);
@@ -8732,32 +8533,13 @@ switch (buf[0]) {
return *ret;
}
goto parse_error;
- case 'i': {
- switch (buf[7]) {
- case 'f':
- if (op == "ref.is_func"sv) {
- auto ret = makeRefTest(ctx, pos, Type(HeapType::func, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'i':
- if (op == "ref.is_i31"sv) {
- auto ret = makeRefTest(ctx, pos, Type(HeapType::i31, NonNullable));
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'n':
- if (op == "ref.is_null"sv) {
- auto ret = makeRefIsNull(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 'i':
+ if (op == "ref.is_null"sv) {
+ auto ret = makeRefIsNull(ctx, pos);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
case 'n':
if (op == "ref.null"sv) {
auto ret = makeRefNull(ctx, pos);
@@ -8765,25 +8547,13 @@ switch (buf[0]) {
return *ret;
}
goto parse_error;
- case 't': {
- switch (buf[8]) {
- case '\0':
- if (op == "ref.test"sv) {
- auto ret = makeRefTest(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '_':
- if (op == "ref.test_static"sv) {
- auto ret = makeRefTest(ctx, pos);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
+ case 't':
+ if (op == "ref.test"sv) {
+ auto ret = makeRefTest(ctx, pos);
+ CHECK_ERR(ret);
+ return *ret;
}
- }
+ goto parse_error;
default: goto parse_error;
}
}
diff --git a/src/ir/stack-utils.h b/src/ir/stack-utils.h
index aad13f7f0..82d1f5a3d 100644
--- a/src/ir/stack-utils.h
+++ b/src/ir/stack-utils.h
@@ -131,13 +131,13 @@ struct StackSignature {
//
// As an example of the first rule, consider this instruction sequence:
//
- // ref.as_func
+ // ref.cast (ref i31)
// drop
// i32.add
//
// The most specific type you could give this sequence is [i32, i32, anyref]
// -> [i32]. But it could also be used in a context that expects [i32, i32,
- // funcref] -> [i32] because ref.as_func can accept funcref or any other
+ // structref] -> [i32] because ref.cast can accept structref or any other
// subtype of anyref. That's where the contravariance comes from. This
// instruction sequence could also be used anywhere that expects [f32, i32,
// i32, anyref] -> [f32, i32] because the f32 simply stays on the stack
@@ -145,7 +145,7 @@ struct StackSignature {
//
// For the second rule, consider this sequence:
//
- // ref.as_func
+ // ref.cast (ref i31)
// drop
// i32.add
// unreachable
diff --git a/src/passes/OptimizeCasts.cpp b/src/passes/OptimizeCasts.cpp
index 599e403ff..7877bea9f 100644
--- a/src/passes/OptimizeCasts.cpp
+++ b/src/passes/OptimizeCasts.cpp
@@ -385,10 +385,8 @@ struct EarlyCastApplier : public PostWalker<EarlyCastApplier> {
auto refCastIter = finder.refCastToApply.find(curr);
if (refCastIter != finder.refCastToApply.end()) {
- currPtr = replaceCurrent(Builder(*getModule())
- .makeRefCast(currPtr,
- refCastIter->second->type,
- refCastIter->second->safety));
+ currPtr = replaceCurrent(
+ Builder(*getModule()).makeRefCast(currPtr, refCastIter->second->type));
}
auto refAsIter = finder.refAsToApply.find(curr);
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 44078545b..965f8b2d8 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1406,13 +1406,13 @@ struct OptimizeInstructions
// skipCast do): removing a cast is potentially dangerous, as it removes
// information from the IR. For example:
//
- // (ref.is_func
- // (ref.as_func
+ // (ref.test (ref i31)
+ // (ref.cast (ref i31)
// (local.get $anyref)))
//
// The local has no useful type info here (it is anyref). The cast forces it
- // to be a function, so we know that if we do not trap then the ref.is will
- // definitely be 1. But if we removed the ref.as first (which we can do in
+ // to be an i31, so we know that if we do not trap then the ref.test will
+ // definitely be 1. But if we removed the ref.cast first (which we can do in
// traps-never-happen mode) then we'd not have the type info we need to
// optimize that way.
//
@@ -1420,12 +1420,12 @@ struct OptimizeInstructions
//
// * Before removing a cast we should use its type information in the best
// way we can. Only after doing so should a cast be removed. In the exmaple
- // above, that means first seeing that the ref.is must return 1, and only
- // then possibly removing the ref.as.
+ // above, that means first seeing that the ref.test must return 1, and only
+ // then possibly removing the ref.cast.
// * Do not remove a cast if removing it might remove useful information for
// others. For example,
//
- // (ref.cast $A
+ // (ref.cast (ref null $A)
// (ref.as_non_null ..))
//
// If we remove the inner cast then the outer cast becomes nullable. That
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 6740bc8ed..dee23d67d 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2102,14 +2102,10 @@ struct PrintExpressionContents
if (printUnreachableReplacement(curr)) {
return;
}
- if (curr->safety == RefCast::Unsafe) {
- printMedium(o, "ref.cast_nop ");
+ if (curr->type.isNullable()) {
+ printMedium(o, "ref.cast null ");
} else {
- if (curr->type.isNullable()) {
- printMedium(o, "ref.cast null ");
- } else {
- printMedium(o, "ref.cast ");
- }
+ printMedium(o, "ref.cast ");
}
printHeapType(o, curr->type.getHeapType(), wasm);
}
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 197126f5e..dc7741c0e 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -714,9 +714,6 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// First, check for a possible null which would prevent optimizations on
// null checks.
- // TODO: Look into using BrOnNonNull here, to replace a br_on_func whose
- // input is (ref null func) with br_on_non_null (as only the null check
- // would be needed).
// TODO: Use the fallthrough to determine in more cases that we
// definitely have a null.
auto refType = curr->ref->type;
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 8df9b9afc..2317e7d49 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -3394,8 +3394,7 @@ Expression* TranslateToFuzzReader::makeRefCast(Type type) {
// This unreachable avoids a warning on refType being possibly undefined.
WASM_UNREACHABLE("bad case");
}
- // TODO: Fuzz unsafe casts?
- return builder.makeRefCast(make(refType), type, RefCast::Safe);
+ return builder.makeRefCast(make(refType), type);
}
Expression* TranslateToFuzzReader::makeStructGet(Type type) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index c6b3e7b6f..05cd38320 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -389,10 +389,6 @@ enum EncodedType {
Array = -0x22, // 0x5e
Sub = -0x30, // 0x50
SubFinal = -0x32, // 0x4e
- // prototype nominal forms we still parse
- FuncSubtype = -0x23, // 0x5d
- StructSubtype = -0x24, // 0x5c
- ArraySubtype = -0x25, // 0x5b
// isorecursive recursion groups
Rec = -0x31, // 0x4f
// block_type
@@ -1108,7 +1104,6 @@ enum ASTNodes {
ArrayGetS = 0x14,
ArrayGetU = 0x15,
ArraySet = 0x16,
- ArrayLenAnnotated = 0x17,
ArrayCopy = 0x18,
ArrayLen = 0x19,
ArrayNewFixed = 0x1a,
@@ -1120,23 +1115,10 @@ enum ASTNodes {
I31GetU = 0x22,
RefTest = 0x40,
RefCast = 0x41,
- BrOnCastLegacy = 0x42,
- BrOnCastFailLegacy = 0x43,
- BrOnCastNullLegacy = 0x4a,
- BrOnCastFailNullLegacy = 0x4b,
BrOnCast = 0x4e,
BrOnCastFail = 0x4f,
- RefTestStatic = 0x44,
- RefCastStatic = 0x45,
RefTestNull = 0x48,
RefCastNull = 0x49,
- RefCastNop = 0x4c,
- RefAsFunc = 0x58,
- RefAsI31 = 0x5a,
- BrOnFunc = 0x60,
- BrOnI31 = 0x62,
- BrOnNonFunc = 0x63,
- BrOnNonI31 = 0x65,
ExternInternalize = 0x70,
ExternExternalize = 0x71,
ArrayFill = 0x0f,
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index a3bf22fdc..cb7c5e745 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -876,13 +876,10 @@ public:
ret->finalize();
return ret;
}
- RefCast* makeRefCast(Expression* ref,
- Type type,
- RefCast::Safety safety = RefCast::Safe) {
+ RefCast* makeRefCast(Expression* ref, Type type) {
auto* ret = wasm.allocator.alloc<RefCast>();
ret->ref = ref;
ret->type = type;
- ret->safety = safety;
ret->finalize();
return ret;
}
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index 1d9d6244d..cd8976f82 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -648,7 +648,6 @@ switch (DELEGATE_ID) {
}
case Expression::Id::RefCastId: {
DELEGATE_START(RefCast);
- DELEGATE_FIELD_INT(RefCast, safety);
DELEGATE_FIELD_CHILD(RefCast, ref);
DELEGATE_END(RefCast);
break;
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index f61a5000a..84299f04b 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -287,14 +287,10 @@ private:
Expression* makeCallRef(Element& s, bool isReturn);
Expression* makeI31New(Element& s);
Expression* makeI31Get(Element& s, bool signed_);
- Expression* makeRefTest(Element& s,
- std::optional<Type> castType = std::nullopt);
- Expression* makeRefCast(Element& s,
- std::optional<Type> castType = std::nullopt);
- Expression* makeRefCastNop(Element& s);
+ Expression* makeRefTest(Element& s);
+ Expression* makeRefCast(Element& s);
Expression* makeBrOnNull(Element& s, bool onFail = false);
- Expression*
- makeBrOnCast(Element& s, std::optional<Type> castType, bool onFail = false);
+ Expression* makeBrOnCast(Element& s, bool onFail = false);
Expression* makeStructNew(Element& s, bool default_);
Index getStructIndex(Element& type, Element& field);
Expression* makeStructGet(Element& s, bool signed_ = false);
diff --git a/src/wasm.h b/src/wasm.h
index c059009b6..39cc9fb54 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1525,11 +1525,6 @@ public:
Expression* ref;
- // Support the unsafe `ref.cast_nop_static` to enable precise cast overhead
- // measurements.
- enum Safety { Safe, Unsafe };
- Safety safety = Safe;
-
void finalize();
Type& getCastType() { return type; }
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 3ceab828b..98e832225 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -2256,49 +2256,15 @@ void WasmBinaryReader::readTypes() {
}
form = getS32LEB();
}
- if (form == BinaryConsts::EncodedType::Func ||
- form == BinaryConsts::EncodedType::FuncSubtype) {
+ if (form == BinaryConsts::EncodedType::Func) {
builder[i] = readSignatureDef();
- } else if (form == BinaryConsts::EncodedType::Struct ||
- form == BinaryConsts::EncodedType::StructSubtype) {
+ } else if (form == BinaryConsts::EncodedType::Struct) {
builder[i] = readStructDef();
- } else if (form == BinaryConsts::EncodedType::Array ||
- form == BinaryConsts::EncodedType::ArraySubtype) {
+ } else if (form == BinaryConsts::EncodedType::Array) {
builder[i] = Array(readFieldDef());
} else {
throwError("Bad type form " + std::to_string(form));
}
- if (form == BinaryConsts::EncodedType::FuncSubtype ||
- form == BinaryConsts::EncodedType::StructSubtype ||
- form == BinaryConsts::EncodedType::ArraySubtype) {
- int64_t super = getS64LEB(); // TODO: Actually s33
- if (super >= 0) {
- superIndex = (uint32_t)super;
- } else {
- // Validate but otherwise ignore trivial supertypes.
- HeapType basicSuper;
- if (!getBasicHeapType(super, basicSuper)) {
- throwError("Unrecognized supertype " + std::to_string(super));
- }
- if (form == BinaryConsts::EncodedType::FuncSubtype) {
- if (basicSuper != HeapType::func) {
- throwError(
- "The only allowed trivial supertype for functions is func");
- }
- } else {
- // Check for "struct" here even if we are parsing an array definition.
- // This is the old nonstandard "struct_subtype" or "array_subtype"
- // form of type definitions that used the old "data" type as the
- // supertype placeholder when there was no nontrivial supertype.
- // "data" no longer exists, but "struct" has the same encoding it used
- // to have.
- if (basicSuper != HeapType::struct_) {
- throwError("The only allowed trivial supertype for structs and "
- "arrays is data");
- }
- }
- }
- }
if (superIndex) {
if (*superIndex > builder.size()) {
throwError("Out of bounds supertype index " +
@@ -4162,12 +4128,6 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) {
if (maybeVisitStringSliceIter(curr, opcode)) {
break;
}
- if (opcode == BinaryConsts::RefAsFunc ||
- opcode == BinaryConsts::RefAsI31) {
- visitRefAsCast((curr = allocator.alloc<RefCast>())->cast<RefCast>(),
- opcode);
- break;
- }
if (opcode == BinaryConsts::ExternInternalize ||
opcode == BinaryConsts::ExternExternalize) {
visitRefAs((curr = allocator.alloc<RefAs>())->cast<RefAs>(), opcode);
@@ -7011,10 +6971,8 @@ bool WasmBinaryReader::maybeVisitI31Get(Expression*& out, uint32_t code) {
}
bool WasmBinaryReader::maybeVisitRefTest(Expression*& out, uint32_t code) {
- if (code == BinaryConsts::RefTestStatic || code == BinaryConsts::RefTest ||
- code == BinaryConsts::RefTestNull) {
- bool legacy = code == BinaryConsts::RefTestStatic;
- auto castType = legacy ? getIndexedHeapType() : getHeapType();
+ if (code == BinaryConsts::RefTest || code == BinaryConsts::RefTestNull) {
+ auto castType = getHeapType();
auto nullability =
(code == BinaryConsts::RefTestNull) ? Nullable : NonNullable;
auto* ref = popNonVoidExpression();
@@ -7024,40 +6982,13 @@ bool WasmBinaryReader::maybeVisitRefTest(Expression*& out, uint32_t code) {
return false;
}
-void WasmBinaryReader::visitRefAsCast(RefCast* curr, uint32_t code) {
- // TODO: These instructions are deprecated. Remove them.
- switch (code) {
- case BinaryConsts::RefAsFunc:
- curr->type = Type(HeapType::func, NonNullable);
- break;
- case BinaryConsts::RefAsI31:
- curr->type = Type(HeapType::i31, NonNullable);
- break;
- default:
- WASM_UNREACHABLE("unexpected ref.as*");
- }
- curr->ref = popNonVoidExpression();
- curr->safety = RefCast::Safe;
- curr->finalize();
-}
-
bool WasmBinaryReader::maybeVisitRefCast(Expression*& out, uint32_t code) {
- if (code == BinaryConsts::RefCastStatic || code == BinaryConsts::RefCast ||
- code == BinaryConsts::RefCastNull || code == BinaryConsts::RefCastNop) {
- bool legacy = code == BinaryConsts::RefCastStatic;
- auto heapType = legacy ? getIndexedHeapType() : getHeapType();
- auto* ref = popNonVoidExpression();
- Nullability nullability;
- if (legacy) {
- // Legacy polymorphic behavior.
- nullability = ref->type.getNullability();
- } else {
- nullability = code == BinaryConsts::RefCast ? NonNullable : Nullable;
- }
- auto safety =
- code == BinaryConsts::RefCastNop ? RefCast::Unsafe : RefCast::Safe;
+ if (code == BinaryConsts::RefCast || code == BinaryConsts::RefCastNull) {
+ auto heapType = getHeapType();
+ auto nullability = code == BinaryConsts::RefCast ? NonNullable : Nullable;
auto type = Type(heapType, nullability);
- out = Builder(wasm).makeRefCast(ref, type, safety);
+ auto* ref = popNonVoidExpression();
+ out = Builder(wasm).makeRefCast(ref, type);
return true;
}
return false;
@@ -7074,63 +7005,32 @@ bool WasmBinaryReader::maybeVisitBrOn(Expression*& out, uint32_t code) {
op = BrOnNonNull;
break;
case BinaryConsts::BrOnCast:
- case BinaryConsts::BrOnCastLegacy:
- case BinaryConsts::BrOnCastNullLegacy:
op = BrOnCast;
break;
case BinaryConsts::BrOnCastFail:
- case BinaryConsts::BrOnCastFailLegacy:
- case BinaryConsts::BrOnCastFailNullLegacy:
op = BrOnCastFail;
break;
- case BinaryConsts::BrOnFunc:
- op = BrOnCast;
- castType = Type(HeapType::func, NonNullable);
- break;
- case BinaryConsts::BrOnNonFunc:
- op = BrOnCastFail;
- castType = Type(HeapType::func, NonNullable);
- break;
- case BinaryConsts::BrOnI31:
- op = BrOnCast;
- castType = Type(HeapType::i31, NonNullable);
- break;
- case BinaryConsts::BrOnNonI31:
- op = BrOnCastFail;
- castType = Type(HeapType::i31, NonNullable);
- break;
default:
return false;
}
- bool hasInputAnnotation =
+ bool isCast =
code == BinaryConsts::BrOnCast || code == BinaryConsts::BrOnCastFail;
uint8_t flags = 0;
- if (hasInputAnnotation) {
+ if (isCast) {
flags = getInt8();
}
auto name = getBreakTarget(getU32LEB()).name;
auto* ref = popNonVoidExpression();
- if (op == BrOnCast || op == BrOnCastFail) {
- Nullability inputNullability, castNullability;
- HeapType inputHeapType, castHeapType;
- if (hasInputAnnotation) {
- inputNullability = (flags & 1) ? Nullable : NonNullable;
- castNullability = (flags & 2) ? Nullable : NonNullable;
- inputHeapType = getHeapType();
- } else {
- castNullability = (code == BinaryConsts::BrOnCastNullLegacy ||
- code == BinaryConsts::BrOnCastFailNullLegacy)
- ? Nullable
- : NonNullable;
- }
- castHeapType = getHeapType();
+ if (isCast) {
+ auto inputNullability = (flags & 1) ? Nullable : NonNullable;
+ auto castNullability = (flags & 2) ? Nullable : NonNullable;
+ auto inputHeapType = getHeapType();
+ auto castHeapType = getHeapType();
castType = Type(castHeapType, castNullability);
- if (hasInputAnnotation) {
- auto inputType = Type(inputHeapType, inputNullability);
- if (!Type::isSubType(ref->type, inputType)) {
- throwError(std::string("Invalid reference type for ") +
- ((op == BrOnCast) ? "br_on_cast" : "br_on_cast_fail"));
- }
+ auto inputType = Type(inputHeapType, inputNullability);
+ if (!Type::isSubType(ref->type, inputType)) {
+ throwError(std::string("Invalid reference type for ") +
+ ((op == BrOnCast) ? "br_on_cast" : "br_on_cast_fail"));
}
}
out = Builder(wasm).makeBrOn(op, name, ref, castType);
@@ -7288,10 +7188,7 @@ bool WasmBinaryReader::maybeVisitArraySet(Expression*& out, uint32_t code) {
}
bool WasmBinaryReader::maybeVisitArrayLen(Expression*& out, uint32_t code) {
- if (code == BinaryConsts::ArrayLenAnnotated) {
- // Ignore the type annotation and don't bother validating it.
- getU32LEB();
- } else if (code != BinaryConsts::ArrayLen) {
+ if (code != BinaryConsts::ArrayLen) {
return false;
}
auto* ref = popNonVoidExpression();
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 9b7a1a90d..0115cdac3 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2841,51 +2841,30 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefTest(Element& s,
- std::optional<Type> castType) {
+Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
int i = 1;
- if (!castType) {
- auto nullability = NonNullable;
- if (s[0]->str().str != "ref.test_static" && s[1]->str().str == "null") {
- nullability = Nullable;
- ++i;
- }
- auto type = parseHeapType(*s[i++]);
- castType = Type(type, nullability);
+ auto nullability = NonNullable;
+ if (s[1]->str().str == "null") {
+ nullability = Nullable;
+ ++i;
}
+ auto type = parseHeapType(*s[i++]);
+ auto castType = Type(type, nullability);
auto* ref = parseExpression(*s[i++]);
- return Builder(wasm).makeRefTest(ref, *castType);
+ return Builder(wasm).makeRefTest(ref, castType);
}
-Expression* SExpressionWasmBuilder::makeRefCast(Element& s,
- std::optional<Type> castType) {
+Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
int i = 1;
- bool legacy = false;
- if (!castType) {
- Nullability nullability = NonNullable;
- if (s[0]->str().str == "ref.cast_static") {
- legacy = true;
- } else if (s[i]->str().str == "null") {
- nullability = Nullable;
- ++i;
- }
- auto type = parseHeapType(*s[i++]);
- castType = Type(type, nullability);
+ Nullability nullability = NonNullable;
+ if (s[i]->str().str == "null") {
+ nullability = Nullable;
+ ++i;
}
+ auto type = parseHeapType(*s[i++]);
+ auto castType = Type(type, nullability);
auto* ref = parseExpression(*s[i++]);
- if (legacy) {
- // Legacy polymorphic behavior.
- castType = Type(castType->getHeapType(), ref->type.getNullability());
- }
- return Builder(wasm).makeRefCast(ref, *castType, RefCast::Safe);
-}
-
-Expression* SExpressionWasmBuilder::makeRefCastNop(Element& s) {
- auto heapType = parseHeapType(*s[1]);
- auto* ref = parseExpression(*s[2]);
- // Legacy polymorphic behavior.
- auto type = Type(heapType, ref->type.getNullability());
- return Builder(wasm).makeRefCast(ref, type, RefCast::Unsafe);
+ return Builder(wasm).makeRefCast(ref, castType);
}
Expression* SExpressionWasmBuilder::makeBrOnNull(Element& s, bool onFail) {
@@ -2896,23 +2875,18 @@ Expression* SExpressionWasmBuilder::makeBrOnNull(Element& s, bool onFail) {
return Builder(wasm).makeBrOn(op, name, ref);
}
-Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s,
- std::optional<Type> castType,
- bool onFail) {
+Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s, bool onFail) {
int i = 1;
auto name = getLabel(*s[i++]);
- std::optional<Type> inputType;
- if (!castType) {
- inputType = elementToType(*s[i++]);
- castType = elementToType(*s[i++]);
- }
+ auto inputType = elementToType(*s[i++]);
+ auto castType = elementToType(*s[i++]);
auto* ref = parseExpression(*s[i]);
- if (inputType && !Type::isSubType(ref->type, *inputType)) {
+ if (!Type::isSubType(ref->type, inputType)) {
throw ParseException(
"br_on_cast* ref type does not match expected type", s.line, s.col);
}
auto op = onFail ? BrOnCastFail : BrOnCast;
- return Builder(wasm).makeBrOn(op, name, ref, *castType);
+ return Builder(wasm).makeBrOn(op, name, ref, castType);
}
Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index ee457da69..3b7756992 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2021,17 +2021,12 @@ void BinaryInstWriter::visitRefTest(RefTest* curr) {
void BinaryInstWriter::visitRefCast(RefCast* curr) {
o << int8_t(BinaryConsts::GCPrefix);
- if (curr->safety == RefCast::Unsafe) {
- o << U32LEB(BinaryConsts::RefCastNop);
- parent.writeHeapType(curr->type.getHeapType());
+ if (curr->type.isNullable()) {
+ o << U32LEB(BinaryConsts::RefCastNull);
} else {
- if (curr->type.isNullable()) {
- o << U32LEB(BinaryConsts::RefCastNull);
- } else {
- o << U32LEB(BinaryConsts::RefCast);
- }
- parent.writeHeapType(curr->type.getHeapType());
+ o << U32LEB(BinaryConsts::RefCast);
}
+ parent.writeHeapType(curr->type.getHeapType());
}
void BinaryInstWriter::visitBrOn(BrOn* curr) {
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index 528d0d1af..d5bda85fe 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -2374,18 +2374,12 @@ Result<typename Ctx::InstrT> makeCallRef(Ctx&, Index, bool isReturn);
template<typename Ctx> Result<typename Ctx::InstrT> makeI31New(Ctx&, Index);
template<typename Ctx>
Result<typename Ctx::InstrT> makeI31Get(Ctx&, Index, bool signed_);
-template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeRefTest(Ctx&, Index, std::optional<Type> castType = std::nullopt);
-template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeRefCast(Ctx&, Index, std::optional<Type> castType = std::nullopt);
-template<typename Ctx> Result<typename Ctx::InstrT> makeRefCastNop(Ctx&, Index);
+template<typename Ctx> Result<typename Ctx::InstrT> makeRefTest(Ctx&, Index);
+template<typename Ctx> Result<typename Ctx::InstrT> makeRefCast(Ctx&, Index);
template<typename Ctx>
Result<typename Ctx::InstrT> makeBrOnNull(Ctx&, Index, bool onFail = false);
template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeBrOnCast(Ctx&, Index, std::optional<Type>, bool onFail = false);
+Result<typename Ctx::InstrT> makeBrOnCast(Ctx&, Index, bool onFail = false);
template<typename Ctx>
Result<typename Ctx::InstrT> makeStructNew(Ctx&, Index, bool default_);
template<typename Ctx>
@@ -3480,19 +3474,12 @@ Result<typename Ctx::InstrT> makeI31Get(Ctx& ctx, Index pos, bool signed_) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeRefTest(Ctx& ctx, Index pos, std::optional<Type> castType) {
- return ctx.in.err("unimplemented instruction");
-}
-
-template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeRefCast(Ctx& ctx, Index pos, std::optional<Type> castType) {
+Result<typename Ctx::InstrT> makeRefTest(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefCastNop(Ctx& ctx, Index pos) {
+Result<typename Ctx::InstrT> makeRefCast(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}
@@ -3502,8 +3489,7 @@ Result<typename Ctx::InstrT> makeBrOnNull(Ctx& ctx, Index pos, bool onFail) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT>
-makeBrOnCast(Ctx& ctx, Index pos, std::optional<Type> castType, bool onFail) {
+Result<typename Ctx::InstrT> makeBrOnCast(Ctx& ctx, Index pos, bool onFail) {
return ctx.in.err("unimplemented instruction");
}