summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp37
-rw-r--r--src/binaryen-c.h24
-rw-r--r--src/gen-s-parser.inc16
-rw-r--r--src/ir/ReFinalize.cpp2
-rw-r--r--src/ir/boolean.h4
-rw-r--r--src/ir/cost.h2
-rw-r--r--src/ir/effects.h2
-rw-r--r--src/ir/gc-type-utils.h18
-rw-r--r--src/ir/possible-contents.cpp2
-rw-r--r--src/js/binaryen.js-post.js34
-rw-r--r--src/passes/Inlining.cpp2
-rw-r--r--src/passes/OptimizeInstructions.cpp81
-rw-r--r--src/passes/Print.cpp36
-rw-r--r--src/tools/fuzzing/fuzzing.cpp3
-rw-r--r--src/wasm-binary.h3
-rw-r--r--src/wasm-builder.h5
-rw-r--r--src/wasm-delegations-fields.def9
-rw-r--r--src/wasm-delegations.def2
-rw-r--r--src/wasm-interpreter.h17
-rw-r--r--src/wasm-s-parser.h5
-rw-r--r--src/wasm.h16
-rw-r--r--src/wasm/wasm-binary.cpp24
-rw-r--r--src/wasm/wasm-s-parser.cpp23
-rw-r--r--src/wasm/wasm-stack.cpp36
-rw-r--r--src/wasm/wasm-validator.cpp13
-rw-r--r--src/wasm/wasm.cpp2
-rw-r--r--src/wasm/wat-parser.cpp21
-rw-r--r--src/wasm2js.h2
28 files changed, 158 insertions, 283 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 7ff827aac..416c8d45b 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1008,10 +1008,6 @@ BinaryenOp BinaryenPromoteLowVecF32x4ToVecF64x2(void) {
return PromoteLowVecF32x4ToVecF64x2;
}
BinaryenOp BinaryenSwizzleVecI8x16(void) { return SwizzleVecI8x16; }
-BinaryenOp BinaryenRefIsNull(void) { return RefIsNull; }
-BinaryenOp BinaryenRefIsFunc(void) { return RefIsFunc; }
-BinaryenOp BinaryenRefIsData(void) { return RefIsData; }
-BinaryenOp BinaryenRefIsI31(void) { return RefIsI31; }
BinaryenOp BinaryenRefAsNonNull(void) { return RefAsNonNull; }
BinaryenOp BinaryenRefAsFunc(void) { return RefAsFunc; }
BinaryenOp BinaryenRefAsData(void) { return RefAsData; }
@@ -1598,11 +1594,10 @@ BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
Builder(*(Module*)module).makeRefNull(type_.getHeapType()));
}
-BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
- BinaryenOp op,
- BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
+ BinaryenExpressionRef value) {
return static_cast<Expression*>(
- Builder(*(Module*)module).makeRefIs(RefIsOp(op), (Expression*)value));
+ Builder(*(Module*)module).makeRefIsNull((Expression*)value));
}
BinaryenExpressionRef BinaryenRefAs(BinaryenModuleRef module,
@@ -3579,28 +3574,18 @@ void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
assert(sizeExpr);
static_cast<MemoryFill*>(expression)->size = (Expression*)sizeExpr;
}
-// RefIs
-BinaryenOp BinaryenRefIsGetOp(BinaryenExpressionRef expr) {
- auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- return static_cast<RefIs*>(expression)->op;
-}
-void BinaryenRefIsSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+// RefIsNull
+BinaryenExpressionRef BinaryenRefIsNullGetValue(BinaryenExpressionRef expr) {
auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- static_cast<RefIs*>(expression)->op = RefIsOp(op);
+ assert(expression->is<RefIsNull>());
+ return static_cast<RefIsNull*>(expression)->value;
}
-BinaryenExpressionRef BinaryenRefIsGetValue(BinaryenExpressionRef expr) {
- auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- return static_cast<RefIs*>(expression)->value;
-}
-void BinaryenRefIsSetValue(BinaryenExpressionRef expr,
- BinaryenExpressionRef valueExpr) {
+void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+ BinaryenExpressionRef valueExpr) {
auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
+ assert(expression->is<RefIsNull>());
assert(valueExpr);
- static_cast<RefIs*>(expression)->value = (Expression*)valueExpr;
+ static_cast<RefIsNull*>(expression)->value = (Expression*)valueExpr;
}
// RefAs
BinaryenOp BinaryenRefAsGetOp(BinaryenExpressionRef expr) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 171d1248d..2c861a141 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -670,10 +670,6 @@ BINARYEN_API BinaryenOp BinaryenTruncSatZeroUVecF64x2ToVecI32x4(void);
BINARYEN_API BinaryenOp BinaryenDemoteZeroVecF64x2ToVecF32x4(void);
BINARYEN_API BinaryenOp BinaryenPromoteLowVecF32x4ToVecF64x2(void);
BINARYEN_API BinaryenOp BinaryenSwizzleVecI8x16(void);
-BINARYEN_API BinaryenOp BinaryenRefIsNull(void);
-BINARYEN_API BinaryenOp BinaryenRefIsFunc(void);
-BINARYEN_API BinaryenOp BinaryenRefIsData(void);
-BINARYEN_API BinaryenOp BinaryenRefIsI31(void);
BINARYEN_API BinaryenOp BinaryenRefAsNonNull(void);
BINARYEN_API BinaryenOp BinaryenRefAsFunc(void);
BINARYEN_API BinaryenOp BinaryenRefAsData(void);
@@ -967,9 +963,8 @@ BinaryenMemoryFill(BinaryenModuleRef module,
const char* memoryName);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
BinaryenType type);
-BINARYEN_API BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
- BinaryenOp op,
- BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
BINARYEN_API BinaryenExpressionRef BinaryenRefAs(BinaryenModuleRef module,
BinaryenOp op,
BinaryenExpressionRef value);
@@ -2092,18 +2087,13 @@ BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);
BINARYEN_API void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
BinaryenExpressionRef sizeExpr);
-// RefIs
+// RefIsNull
-// Gets the operation performed by a `ref.is_*` expression.
-BINARYEN_API BinaryenOp BinaryenRefIsGetOp(BinaryenExpressionRef expr);
-// Sets the operation performed by a `ref.is_*` expression.
-BINARYEN_API void BinaryenRefIsSetOp(BinaryenExpressionRef expr, BinaryenOp op);
-// Gets the value expression tested by a `ref.is_*` expression.
BINARYEN_API BinaryenExpressionRef
-BinaryenRefIsGetValue(BinaryenExpressionRef expr);
-// Sets the value expression tested by a `ref.is_*` expression.
-BINARYEN_API void BinaryenRefIsSetValue(BinaryenExpressionRef expr,
- BinaryenExpressionRef valueExpr);
+BinaryenRefIsNullGetValue(BinaryenExpressionRef expr);
+// Sets the value expression tested by a `ref.is_null` expression.
+BINARYEN_API void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+ BinaryenExpressionRef valueExpr);
// RefAs
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index acae3af50..70644827c 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -3050,16 +3050,16 @@ switch (buf[0]) {
case 'i': {
switch (buf[7]) {
case 'd':
- if (op == "ref.is_data"sv) { return makeRefIs(s, RefIsData); }
+ if (op == "ref.is_data"sv) { return makeRefTest(s, Type(HeapType::data, NonNullable)); }
goto parse_error;
case 'f':
- if (op == "ref.is_func"sv) { return makeRefIs(s, RefIsFunc); }
+ 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 makeRefIs(s, RefIsI31); }
+ 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 makeRefIs(s, RefIsNull); }
+ if (op == "ref.is_null"sv) { return makeRefIsNull(s); }
goto parse_error;
default: goto parse_error;
}
@@ -8689,28 +8689,28 @@ switch (buf[0]) {
switch (buf[7]) {
case 'd':
if (op == "ref.is_data"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsData);
+ auto ret = makeRefTest(ctx, pos, Type(HeapType::data, NonNullable));
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case 'f':
if (op == "ref.is_func"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsFunc);
+ 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 = makeRefIs(ctx, pos, RefIsI31);
+ 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 = makeRefIs(ctx, pos, RefIsNull);
+ auto ret = makeRefIsNull(ctx, pos);
CHECK_ERR(ret);
return *ret;
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 5ae6a67ce..a5651c6b6 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -128,7 +128,7 @@ void ReFinalize::visitReturn(Return* curr) { curr->finalize(); }
void ReFinalize::visitMemorySize(MemorySize* curr) { curr->finalize(); }
void ReFinalize::visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); }
void ReFinalize::visitRefNull(RefNull* curr) { curr->finalize(); }
-void ReFinalize::visitRefIs(RefIs* curr) { curr->finalize(); }
+void ReFinalize::visitRefIsNull(RefIsNull* curr) { curr->finalize(); }
void ReFinalize::visitRefFunc(RefFunc* curr) {
// TODO: should we look up the function and update the type from there? This
// could handle a change to the function's type, but is also not really what
diff --git a/src/ir/boolean.h b/src/ir/boolean.h
index 58601c2ce..68dfb8b32 100644
--- a/src/ir/boolean.h
+++ b/src/ir/boolean.h
@@ -26,8 +26,8 @@ inline bool emitsBoolean(Expression* curr) {
return unary->isRelational();
} else if (auto* binary = curr->dynCast<Binary>()) {
return binary->isRelational();
- } else if (curr->is<RefIs>() || curr->is<RefEq>() || curr->is<RefTest>() ||
- curr->is<StringEq>()) {
+ } else if (curr->is<RefIsNull>() || curr->is<RefEq>() ||
+ curr->is<RefTest>() || curr->is<StringEq>()) {
return true;
}
return false;
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 59b738b1b..11c179d40 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -561,7 +561,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 1 + visit(curr->left) + visit(curr->right);
}
CostType visitRefNull(RefNull* curr) { return 1; }
- CostType visitRefIs(RefIs* curr) { return 1 + visit(curr->value); }
+ CostType visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); }
CostType visitRefFunc(RefFunc* curr) { return 1; }
CostType visitRefEq(RefEq* curr) {
return 1 + visit(curr->left) + visit(curr->right);
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 70e9192c0..4ea577f7a 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -648,7 +648,7 @@ private:
parent.isAtomic = true;
}
void visitRefNull(RefNull* curr) {}
- void visitRefIs(RefIs* curr) {}
+ void visitRefIsNull(RefIsNull* curr) {}
void visitRefFunc(RefFunc* curr) {}
void visitRefEq(RefEq* curr) {}
void visitTableGet(TableGet* curr) {
diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h
index 1646e47c3..5f1b4807c 100644
--- a/src/ir/gc-type-utils.h
+++ b/src/ir/gc-type-utils.h
@@ -75,24 +75,6 @@ inline EvaluationResult evaluateKindCheck(Expression* curr) {
WASM_UNREACHABLE("unhandled BrOn");
}
child = br->ref;
- } else if (auto* is = curr->dynCast<RefIs>()) {
- switch (is->op) {
- // We don't check nullability here.
- case RefIsNull:
- return Unknown;
- case RefIsFunc:
- expected = Func;
- break;
- case RefIsData:
- expected = Data;
- break;
- case RefIsI31:
- expected = I31;
- break;
- default:
- WASM_UNREACHABLE("unhandled RefIs");
- }
- child = is->value;
} else if (auto* as = curr->dynCast<RefAs>()) {
switch (as->op) {
// We don't check nullability here.
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 52b05057f..cf30cd917 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -587,7 +587,7 @@ struct InfoCollector
curr,
PossibleContents::literal(Literal::makeNull(curr->type.getHeapType())));
}
- void visitRefIs(RefIs* curr) {
+ void visitRefIsNull(RefIsNull* curr) {
// TODO: Optimize when possible. For example, if we can infer an exact type
// here which allows us to know the result then we should do so. This
// is unlike the case in visitUnary, above: the information that lets
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index d4395359e..2a08c5e5a 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -92,7 +92,7 @@ function initializeConstants() {
'MemoryCopy',
'MemoryFill',
'RefNull',
- 'RefIs',
+ 'RefIsNull',
'RefFunc',
'RefEq',
'TableGet',
@@ -549,10 +549,6 @@ function initializeConstants() {
'DemoteZeroVecF64x2ToVecF32x4',
'PromoteLowVecF32x4ToVecF64x2',
'SwizzleVecI8x16',
- 'RefIsNull',
- 'RefIsFunc',
- 'RefIsData',
- 'RefIsI31',
'RefAsNonNull',
'RefAsFunc',
'RefAsData',
@@ -2344,16 +2340,7 @@ function wrapModule(module, self = {}) {
return Module['_BinaryenRefNull'](module, type);
},
'is_null'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsNull'], value);
- },
- 'is_func'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsFunc'], value);
- },
- 'is_data'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsData'], value);
- },
- 'is_i31'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsI31'], value);
+ return Module['_BinaryenRefIsNull'](module, value);
},
'as_non_null'(value) {
return Module['_BinaryenRefAs'](module, Module['RefAsNonNull'], value);
@@ -3203,12 +3190,11 @@ Module['getExpressionInfo'] = function(expr) {
'id': id,
'type': type
};
- case Module['RefIsId']:
+ case Module['RefIsNullId']:
return {
'id': id,
'type': type,
- 'op': Module['_BinaryenRefIsGetOp'](expr),
- 'value': Module['_BinaryenRefIsGetValue'](expr)
+ 'value': Module['_BinaryenRefIsNullGetValue'](expr)
};
case Module['RefAsId']:
return {
@@ -4622,18 +4608,12 @@ Module['MemoryFill'] = makeExpressionWrapper({
}
});
-Module['RefIs'] = makeExpressionWrapper({
- 'getOp'(expr) {
- return Module['_BinaryenRefIsGetOp'](expr);
- },
- 'setOp'(expr, op) {
- Module['_BinaryenRefIsSetOp'](expr, op);
- },
+Module['RefIsNull'] = makeExpressionWrapper({
'getValue'(expr) {
- return Module['_BinaryenRefIsGetValue'](expr);
+ return Module['_BinaryenRefIsNullGetValue'](expr);
},
'setValue'(expr, valueExpr) {
- Module['_BinaryenRefIsSetValue'](expr, valueExpr);
+ Module['_BinaryenRefIsNullSetValue'](expr, valueExpr);
}
});
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 41083567c..4475db7b0 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -834,7 +834,7 @@ private:
if (auto* unary = curr->dynCast<Unary>()) {
return isSimple(unary->value);
}
- if (auto* is = curr->dynCast<RefIs>()) {
+ if (auto* is = curr->dynCast<RefIsNull>()) {
return isSimple(is->value);
}
return false;
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 7902eaebd..36f5fbc25 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1705,7 +1705,7 @@ struct OptimizeInstructions
// RefEq of a value to Null can be replaced with RefIsNull.
if (curr->right->is<RefNull>()) {
- replaceCurrent(Builder(*getModule()).makeRefIs(RefIsNull, curr->left));
+ replaceCurrent(Builder(*getModule()).makeRefIsNull(curr->left));
}
}
@@ -2154,78 +2154,27 @@ struct OptimizeInstructions
}
}
- void visitRefIs(RefIs* curr) {
+ void visitRefIsNull(RefIsNull* curr) {
if (curr->type == Type::unreachable) {
return;
}
- // Optimizating RefIs is not that obvious, since even if we know the result
- // evaluates to 0 or 1 then the replacement may not actually save code size,
- // since RefIsNull is a single byte (the others are 2), while adding a Const
- // of 0 would be two bytes. Other factors are that we can remove the input
- // and the added drop on it if it has no side effects, and that replacing
- // with a constant may allow further optimizations later. For now, replace
- // with a constant, but this warrants more investigation. TODO
+ // Optimizing RefIsNull is not that obvious, since even if we know the
+ // result evaluates to 0 or 1 then the replacement may not actually save
+ // code size, since RefIsNull is a single byte while adding a Const of 0
+ // would be two bytes. Other factors are that we can remove the input and
+ // the added drop on it if it has no side effects, and that replacing with a
+ // constant may allow further optimizations later. For now, replace with a
+ // constant, but this warrants more investigation. TODO
Builder builder(*getModule());
-
- auto nonNull = !curr->value->type.isNullable();
-
- if (curr->op == RefIsNull) {
- if (nonNull) {
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeZero(Type::i32))));
- } else {
- // See the comment on the other call to this lower down. Because of that
- // other code path we run this optimization at the end (though in this
- // code path it would be fine either way).
- skipCast(curr->value);
- }
- return;
- }
-
- // Check if the type is the kind we are checking for.
- auto result = GCTypeUtils::evaluateKindCheck(curr);
-
- if (result != GCTypeUtils::Unknown) {
- // We know the kind. Now we must also take into account nullability.
- if (nonNull) {
- // We know the entire result.
- replaceCurrent(
- builder.makeSequence(builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeFromInt32(
- result == GCTypeUtils::Success, Type::i32))));
- } else {
- // The value may be null. Leave only a check for that.
- curr->op = RefIsNull;
- if (result == GCTypeUtils::Success) {
- // The input is of the right kind. If it is not null then the result
- // is 1, and otherwise it is 0, so we need to flip the result of
- // RefIsNull.
- // Note that even after adding an eqz here we do not regress code size
- // as RefIsNull is a single byte while the others are two. So we keep
- // code size identical. However, in theory this may be more work, if
- // a VM considers ref.is_X to be as fast as ref.is_null, and if eqz is
- // not free, so this is worth more investigation. TODO
- replaceCurrent(builder.makeUnary(EqZInt32, curr));
- } else {
- // The input is of the wrong kind. In this case if it is null we
- // return zero because of that, and if it is not then we return zero
- // because of the kind, so the result is always the same.
- assert(result == GCTypeUtils::Failure);
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeZero(Type::i32))));
- }
- }
+ if (curr->value->type.isNonNullable()) {
+ replaceCurrent(
+ builder.makeSequence(builder.makeDrop(curr->value),
+ builder.makeConst(Literal::makeZero(Type::i32))));
+ } else {
+ skipCast(curr->value);
}
-
- // What the reference points to does not depend on the type, so casts
- // may be removable. Do this right before returning because removing a
- // cast may remove info that we could have used to optimize, see
- // "notes on removing casts".
- skipCast(curr->value);
}
void visitRefAs(RefAs* curr) {
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 988b1d251..12c185e69 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2000,24 +2000,7 @@ struct PrintExpressionContents
printMedium(o, "ref.null ");
printHeapType(o, curr->type.getHeapType(), wasm);
}
- void visitRefIs(RefIs* curr) {
- switch (curr->op) {
- case RefIsNull:
- printMedium(o, "ref.is_null");
- break;
- case RefIsFunc:
- printMedium(o, "ref.is_func");
- break;
- case RefIsData:
- printMedium(o, "ref.is_data");
- break;
- case RefIsI31:
- printMedium(o, "ref.is_i31");
- break;
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
- }
+ void visitRefIsNull(RefIsNull* curr) { printMedium(o, "ref.is_null"); }
void visitRefFunc(RefFunc* curr) {
printMedium(o, "ref.func ");
printName(curr->func, o);
@@ -2109,6 +2092,23 @@ struct PrintExpressionContents
printHeapType(o, curr->target->type.getHeapType(), wasm);
}
void visitRefTest(RefTest* curr) {
+ // TODO: These instructions are deprecated. Remove them.
+ if (auto type = curr->castType.getHeapType();
+ curr->castType.isNonNullable() && type.isBasic()) {
+ switch (type.getBasic()) {
+ case HeapType::func:
+ printMedium(o, "ref.is_func");
+ return;
+ case HeapType::data:
+ printMedium(o, "ref.is_data");
+ return;
+ case HeapType::i31:
+ printMedium(o, "ref.is_i31");
+ return;
+ default:
+ break;
+ }
+ }
printMedium(o, "ref.test ");
if (curr->castType.isNullable()) {
printMedium(o, "null ");
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index cda14c989..18568271b 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -2954,11 +2954,10 @@ Expression* TranslateToFuzzReader::makeBulkMemory(Type type) {
WASM_UNREACHABLE("invalid value");
}
-// TODO: support other RefIs variants, and rename this
Expression* TranslateToFuzzReader::makeRefIsNull(Type type) {
assert(type == Type::i32);
assert(wasm.features.hasReferenceTypes());
- return builder.makeRefIs(RefIsNull, make(getReferenceType()));
+ return builder.makeRefIsNull(make(getReferenceType()));
}
Expression* TranslateToFuzzReader::makeRefEq(Type type) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 303c81128..1a3e5c82b 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1738,7 +1738,8 @@ public:
void visitUnreachable(Unreachable* curr);
void visitDrop(Drop* curr);
void visitRefNull(RefNull* curr);
- void visitRefIs(RefIs* curr, uint8_t code);
+ void visitRefIsNull(RefIsNull* curr);
+ void visitRefIs(RefTest* curr, uint8_t code);
void visitRefFunc(RefFunc* curr);
void visitRefEq(RefEq* curr);
void visitTableGet(TableGet* curr);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 915c189ae..263ee80fd 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -716,9 +716,8 @@ public:
ret->finalize(type);
return ret;
}
- RefIs* makeRefIs(RefIsOp op, Expression* value) {
- auto* ret = wasm.allocator.alloc<RefIs>();
- ret->op = op;
+ RefIsNull* makeRefIsNull(Expression* value) {
+ auto* ret = wasm.allocator.alloc<RefIsNull>();
ret->value = value;
ret->finalize();
return ret;
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index f929def4a..019cdbc0d 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -491,11 +491,10 @@ switch (DELEGATE_ID) {
DELEGATE_END(RefNull);
break;
}
- case Expression::Id::RefIsId: {
- DELEGATE_START(RefIs);
- DELEGATE_FIELD_INT(RefIs, op);
- DELEGATE_FIELD_CHILD(RefIs, value);
- DELEGATE_END(RefIs);
+ case Expression::Id::RefIsNullId: {
+ DELEGATE_START(RefIsNull);
+ DELEGATE_FIELD_CHILD(RefIsNull, value);
+ DELEGATE_END(RefIsNull);
break;
}
case Expression::Id::RefFuncId: {
diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def
index dbdef3a86..d2b5dfa2e 100644
--- a/src/wasm-delegations.def
+++ b/src/wasm-delegations.def
@@ -55,7 +55,7 @@ DELEGATE(MemoryGrow);
DELEGATE(Unreachable);
DELEGATE(Pop);
DELEGATE(RefNull);
-DELEGATE(RefIs);
+DELEGATE(RefIsNull);
DELEGATE(RefFunc);
DELEGATE(RefEq);
DELEGATE(TableGet);
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 181114c92..104f06585 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1336,26 +1336,15 @@ public:
NOTE_ENTER("RefNull");
return Literal::makeNull(curr->type.getHeapType());
}
- Flow visitRefIs(RefIs* curr) {
- NOTE_ENTER("RefIs");
+ Flow visitRefIsNull(RefIsNull* curr) {
+ NOTE_ENTER("RefIsNull");
Flow flow = visit(curr->value);
if (flow.breaking()) {
return flow;
}
const auto& value = flow.getSingleValue();
NOTE_EVAL1(value);
- switch (curr->op) {
- case RefIsNull:
- return Literal(value.isNull());
- case RefIsFunc:
- return Literal(value.type.isFunction());
- case RefIsData:
- return Literal(value.isData());
- case RefIsI31:
- return Literal(value.type.getHeapType() == HeapType::i31);
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
+ return Literal(int32_t(value.isNull()));
}
Flow visitRefFunc(RefFunc* curr) {
NOTE_ENTER("RefFunc");
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 04c832869..6ae3e57be 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -267,7 +267,7 @@ private:
Expression* makeBreakTable(Element& s);
Expression* makeReturn(Element& s);
Expression* makeRefNull(Element& s);
- Expression* makeRefIs(Element& s, RefIsOp op);
+ Expression* makeRefIsNull(Element& s);
Expression* makeRefFunc(Element& s);
Expression* makeRefEq(Element& s);
Expression* makeTableGet(Element& s);
@@ -283,7 +283,8 @@ private:
Expression* makeCallRef(Element& s, bool isReturn);
Expression* makeI31New(Element& s);
Expression* makeI31Get(Element& s, bool signed_);
- Expression* makeRefTest(Element& s);
+ Expression* makeRefTest(Element& s,
+ std::optional<Type> castType = std::nullopt);
Expression* makeRefCast(Element& s);
Expression* makeRefCastNop(Element& s);
Expression* makeBrOnNull(Element& s, bool onFail = false);
diff --git a/src/wasm.h b/src/wasm.h
index ae88bc4d9..7b75ec3b8 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -557,13 +557,6 @@ enum SIMDTernaryOp {
DotI8x16I7x16AddSToVecI32x4,
};
-enum RefIsOp {
- RefIsNull,
- RefIsFunc,
- RefIsData,
- RefIsI31,
-};
-
enum RefAsOp {
RefAsNonNull,
RefAsFunc,
@@ -696,7 +689,7 @@ public:
MemoryFillId,
PopId,
RefNullId,
- RefIsId,
+ RefIsNullId,
RefFuncId,
RefEqId,
TableGetId,
@@ -1346,12 +1339,9 @@ public:
void finalize(Type type);
};
-class RefIs : public SpecificExpression<Expression::RefIsId> {
+class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
public:
- RefIs(MixedArena& allocator) {}
-
- // RefIs can represent ref.is_null, ref.is_func, ref.is_data, and ref.is_i31.
- RefIsOp op;
+ RefIsNull(MixedArena& allocator) {}
Expression* value;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 2639599d5..b1f4b8907 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -3795,7 +3795,7 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
visitRefNull((curr = allocator.alloc<RefNull>())->cast<RefNull>());
break;
case BinaryConsts::RefIsNull:
- visitRefIs((curr = allocator.alloc<RefIs>())->cast<RefIs>(), code);
+ visitRefIsNull((curr = allocator.alloc<RefIsNull>())->cast<RefIsNull>());
break;
case BinaryConsts::RefFunc:
visitRefFunc((curr = allocator.alloc<RefFunc>())->cast<RefFunc>());
@@ -4026,7 +4026,8 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (opcode == BinaryConsts::RefIsFunc ||
opcode == BinaryConsts::RefIsData ||
opcode == BinaryConsts::RefIsI31) {
- visitRefIs((curr = allocator.alloc<RefIs>())->cast<RefIs>(), opcode);
+ visitRefIs((curr = allocator.alloc<RefTest>())->cast<RefTest>(),
+ opcode);
break;
}
if (opcode == BinaryConsts::RefAsFunc ||
@@ -6591,25 +6592,28 @@ void WasmBinaryBuilder::visitRefNull(RefNull* curr) {
curr->finalize(getHeapType().getBottom());
}
-void WasmBinaryBuilder::visitRefIs(RefIs* curr, uint8_t code) {
+void WasmBinaryBuilder::visitRefIsNull(RefIsNull* curr) {
+ BYN_TRACE("zz node: RefIsNull\n");
+ curr->value = popNonVoidExpression();
+ curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRefIs(RefTest* curr, uint8_t code) {
BYN_TRACE("zz node: RefIs\n");
switch (code) {
- case BinaryConsts::RefIsNull:
- curr->op = RefIsNull;
- break;
case BinaryConsts::RefIsFunc:
- curr->op = RefIsFunc;
+ curr->castType = Type(HeapType::func, NonNullable);
break;
case BinaryConsts::RefIsData:
- curr->op = RefIsData;
+ curr->castType = Type(HeapType::data, NonNullable);
break;
case BinaryConsts::RefIsI31:
- curr->op = RefIsI31;
+ curr->castType = Type(HeapType::i31, NonNullable);
break;
default:
WASM_UNREACHABLE("invalid code for ref.is_*");
}
- curr->value = popNonVoidExpression();
+ curr->ref = popNonVoidExpression();
curr->finalize();
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 638dfbebf..4f725d48b 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2536,9 +2536,8 @@ Expression* SExpressionWasmBuilder::makeRefNull(Element& s) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefIs(Element& s, RefIsOp op) {
- auto ret = allocator.alloc<RefIs>();
- ret->op = op;
+Expression* SExpressionWasmBuilder::makeRefIsNull(Element& s) {
+ auto ret = allocator.alloc<RefIsNull>();
ret->value = parseExpression(s[1]);
ret->finalize();
return ret;
@@ -2775,16 +2774,20 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
+Expression* SExpressionWasmBuilder::makeRefTest(Element& s,
+ std::optional<Type> castType) {
int i = 1;
- auto nullability = NonNullable;
- if (s[0]->str().str != "ref.test_static" && s[1]->str().str == "null") {
- nullability = Nullable;
- ++i;
+ 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 heapType = parseHeapType(*s[i++]);
auto* ref = parseExpression(*s[i++]);
- return Builder(wasm).makeRefTest(ref, Type(heapType, nullability));
+ return Builder(wasm).makeRefTest(ref, *castType);
}
Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 24710f206..82c7c511f 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1875,23 +1875,8 @@ void BinaryInstWriter::visitRefNull(RefNull* curr) {
parent.writeHeapType(curr->type.getHeapType());
}
-void BinaryInstWriter::visitRefIs(RefIs* curr) {
- switch (curr->op) {
- case RefIsNull:
- o << int8_t(BinaryConsts::RefIsNull);
- break;
- case RefIsFunc:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsFunc);
- break;
- case RefIsData:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsData);
- break;
- case RefIsI31:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsI31);
- break;
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
+void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) {
+ o << int8_t(BinaryConsts::RefIsNull);
}
void BinaryInstWriter::visitRefFunc(RefFunc* curr) {
@@ -2025,6 +2010,23 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
void BinaryInstWriter::visitRefTest(RefTest* curr) {
o << int8_t(BinaryConsts::GCPrefix);
+ // TODO: These instructions are deprecated. Remove them.
+ if (auto type = curr->castType.getHeapType();
+ curr->castType.isNonNullable() && type.isBasic()) {
+ switch (type.getBasic()) {
+ case HeapType::func:
+ o << U32LEB(BinaryConsts::RefIsFunc);
+ return;
+ case HeapType::data:
+ o << U32LEB(BinaryConsts::RefIsData);
+ return;
+ case HeapType::i31:
+ o << U32LEB(BinaryConsts::RefIsI31);
+ return;
+ default:
+ break;
+ }
+ }
if (curr->castType.isNullable()) {
o << U32LEB(BinaryConsts::RefTestNull);
} else {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 486f13d24..28526cb33 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -427,7 +427,7 @@ public:
void visitMemorySize(MemorySize* curr);
void visitMemoryGrow(MemoryGrow* curr);
void visitRefNull(RefNull* curr);
- void visitRefIs(RefIs* curr);
+ void visitRefIsNull(RefIsNull* curr);
void visitRefAs(RefAs* curr);
void visitRefFunc(RefFunc* curr);
void visitRefEq(RefEq* curr);
@@ -2132,14 +2132,15 @@ void FunctionValidator::visitRefNull(RefNull* curr) {
curr->type.isNull(), curr, "ref.null must have a bottom heap type");
}
-void FunctionValidator::visitRefIs(RefIs* curr) {
- shouldBeTrue(getModule()->features.hasReferenceTypes(),
- curr,
- "ref.is_* requires reference-types [--enable-reference-types]");
+void FunctionValidator::visitRefIsNull(RefIsNull* curr) {
+ shouldBeTrue(
+ getModule()->features.hasReferenceTypes(),
+ curr,
+ "ref.is_null requires reference-types [--enable-reference-types]");
shouldBeTrue(curr->value->type == Type::unreachable ||
curr->value->type.isRef(),
curr->value,
- "ref.is_*'s argument should be a reference type");
+ "ref.is_null's argument should be a reference type");
}
void FunctionValidator::visitRefAs(RefAs* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index c6779a328..c121ba89a 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -805,7 +805,7 @@ void RefNull::finalize(Type type_) { type = type_; }
void RefNull::finalize() {}
-void RefIs::finalize() {
+void RefIsNull::finalize() {
if (value->type == Type::unreachable) {
type = Type::unreachable;
} else {
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index 14d30db1c..08eec41c6 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -758,7 +758,7 @@ struct NullInstrParserCtx {
template<typename HeapTypeT> InstrT makeRefNull(Index, HeapTypeT) {
return Ok{};
}
- InstrT makeRefIs(Index, RefIsOp) { return Ok{}; }
+ InstrT makeRefIsNull(Index) { return Ok{}; }
InstrT makeRefEq(Index) { return Ok{}; }
@@ -2053,10 +2053,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return push(pos, builder.makeRefNull(type));
}
- Result<> makeRefIs(Index pos, RefIsOp op) {
+ Result<> makeRefIsNull(Index pos) {
auto ref = pop(pos);
CHECK_ERR(ref);
- return push(pos, builder.makeRefIs(op, *ref));
+ return push(pos, builder.makeRefIsNull(*ref));
}
Result<> makeRefEq(Index pos) {
@@ -2322,8 +2322,7 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeBreak(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeBreakTable(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeReturn(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefNull(Ctx&, Index);
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefIs(Ctx&, Index, RefIsOp op);
+template<typename Ctx> Result<typename Ctx::InstrT> makeRefIsNull(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefFunc(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefEq(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeTableGet(Ctx&, Index);
@@ -2344,8 +2343,9 @@ 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);
-template<typename Ctx> Result<typename Ctx::InstrT> makeRefTest(Ctx&, Index);
+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);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefCastNop(Ctx&, Index);
template<typename Ctx>
@@ -3357,8 +3357,8 @@ Result<typename Ctx::InstrT> makeRefNull(Ctx& ctx, Index pos) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefIs(Ctx& ctx, Index pos, RefIsOp op) {
- return ctx.makeRefIs(pos, op);
+Result<typename Ctx::InstrT> makeRefIsNull(Ctx& ctx, Index pos) {
+ return ctx.makeRefIsNull(pos);
}
template<typename Ctx>
@@ -3438,7 +3438,8 @@ Result<typename Ctx::InstrT> makeI31Get(Ctx& ctx, Index pos, bool signed_) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefTest(Ctx& ctx, Index pos) {
+Result<typename Ctx::InstrT>
+makeRefTest(Ctx& ctx, Index pos, std::optional<Type> castType) {
return ctx.in.err("unimplemented instruction");
}
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 25931db85..eddb26866 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -2206,7 +2206,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
- Ref visitRefIs(RefIs* curr) {
+ Ref visitRefIsNull(RefIsNull* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}