diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 37 | ||||
-rw-r--r-- | src/binaryen-c.h | 24 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 16 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 2 | ||||
-rw-r--r-- | src/ir/boolean.h | 4 | ||||
-rw-r--r-- | src/ir/cost.h | 2 | ||||
-rw-r--r-- | src/ir/effects.h | 2 | ||||
-rw-r--r-- | src/ir/gc-type-utils.h | 18 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 34 | ||||
-rw-r--r-- | src/passes/Inlining.cpp | 2 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 81 | ||||
-rw-r--r-- | src/passes/Print.cpp | 36 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 3 | ||||
-rw-r--r-- | src/wasm-binary.h | 3 | ||||
-rw-r--r-- | src/wasm-builder.h | 5 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 9 | ||||
-rw-r--r-- | src/wasm-delegations.def | 2 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 17 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 5 | ||||
-rw-r--r-- | src/wasm.h | 16 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 24 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 23 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 36 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 13 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 21 | ||||
-rw-r--r-- | src/wasm2js.h | 2 |
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"); } |