diff options
38 files changed, 402 insertions, 482 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 80534dab8..47b8798cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ Current Trunk basic subtyping of `externref`, `funcref` and `exnref` (if enabled). - Enabling the exception handling or anyref features without also enabling reference types is a validation error now. +- The `Host` expression and its respective APIs have been refactored into + separate `MemorySize` and `MemoryGrow` expressions to align with other memory + instructions. v96 --- diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index db0dbc66f..d66f10852 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -66,8 +66,8 @@ instructions = [ ("i64.store8", "makeStore(s, Type::i64, /*isAtomic=*/false)"), ("i64.store16", "makeStore(s, Type::i64, /*isAtomic=*/false)"), ("i64.store32", "makeStore(s, Type::i64, /*isAtomic=*/false)"), - ("memory.size", "makeHost(s, HostOp::MemorySize)"), - ("memory.grow", "makeHost(s, HostOp::MemoryGrow)"), + ("memory.size", "makeMemorySize(s)"), + ("memory.grow", "makeMemoryGrow(s)"), ("i32.const", "makeConst(s, Type::i32)"), ("i64.const", "makeConst(s, Type::i64)"), ("f32.const", "makeConst(s, Type::f32)"), diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 3084ae2ae..e833692d5 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -199,7 +199,12 @@ BinaryenExpressionId BinaryenBinaryId(void) { return Expression::Id::BinaryId; } BinaryenExpressionId BinaryenSelectId(void) { return Expression::Id::SelectId; } BinaryenExpressionId BinaryenDropId(void) { return Expression::Id::DropId; } BinaryenExpressionId BinaryenReturnId(void) { return Expression::Id::ReturnId; } -BinaryenExpressionId BinaryenHostId(void) { return Expression::Id::HostId; } +BinaryenExpressionId BinaryenMemorySizeId(void) { + return Expression::Id::MemorySizeId; +} +BinaryenExpressionId BinaryenMemoryGrowId(void) { + return Expression::Id::MemoryGrowId; +} BinaryenExpressionId BinaryenNopId(void) { return Expression::Id::NopId; } BinaryenExpressionId BinaryenUnreachableId(void) { return Expression::Id::UnreachableId; @@ -509,8 +514,6 @@ BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; } BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; } BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; } BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; } -BinaryenOp BinaryenMemorySize(void) { return MemorySize; } -BinaryenOp BinaryenMemoryGrow(void) { return MemoryGrow; } BinaryenOp BinaryenAtomicRMWAdd(void) { return AtomicRMWOp::Add; } BinaryenOp BinaryenAtomicRMWSub(void) { return AtomicRMWOp::Sub; } BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; } @@ -1056,20 +1059,13 @@ BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, auto* ret = Builder(*(Module*)module).makeReturn((Expression*)value); return static_cast<Expression*>(ret); } -BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, - BinaryenOp op, - const char* name, - BinaryenExpressionRef* operands, - BinaryenIndex numOperands) { - auto* ret = ((Module*)module)->allocator.alloc<Host>(); - ret->op = HostOp(op); - if (name) { - ret->nameOperand = name; - } - for (BinaryenIndex i = 0; i < numOperands; i++) { - ret->operands.push_back((Expression*)operands[i]); - } - ret->finalize(); +BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module) { + auto* ret = Builder(*(Module*)module).makeMemorySize(); + return static_cast<Expression*>(ret); +} +BinaryenExpressionRef BinaryenMemoryGrow(BinaryenModuleRef module, + BinaryenExpressionRef delta) { + auto* ret = Builder(*(Module*)module).makeMemoryGrow((Expression*)delta); return static_cast<Expression*>(ret); } BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module) { @@ -1826,72 +1822,18 @@ void BinaryenGlobalSetSetValue(BinaryenExpressionRef expr, assert(valueExpr); static_cast<GlobalSet*>(expression)->value = (Expression*)valueExpr; } -// Host -BinaryenOp BinaryenHostGetOp(BinaryenExpressionRef expr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - return static_cast<Host*>(expression)->op; -} -void BinaryenHostSetOp(BinaryenExpressionRef expr, BinaryenOp op) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - static_cast<Host*>(expression)->op = (HostOp)op; -} -const char* BinaryenHostGetNameOperand(BinaryenExpressionRef expr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - return static_cast<Host*>(expression)->nameOperand.c_str(); -} -void BinaryenHostSetNameOperand(BinaryenExpressionRef expr, const char* name) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - static_cast<Host*>(expression)->nameOperand = name ? name : ""; -} -BinaryenIndex BinaryenHostGetNumOperands(BinaryenExpressionRef expr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - return static_cast<Host*>(expression)->operands.size(); -} -BinaryenExpressionRef BinaryenHostGetOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index) { +// MemoryGrow +BinaryenExpressionRef BinaryenMemoryGrowGetDelta(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - assert(index < static_cast<Host*>(expression)->operands.size()); - return static_cast<Host*>(expression)->operands[index]; + assert(expression->is<MemoryGrow>()); + return static_cast<MemoryGrow*>(expression)->delta; } -void BinaryenHostSetOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index, - BinaryenExpressionRef operandExpr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - assert(index < static_cast<Host*>(expression)->operands.size()); - assert(operandExpr); - static_cast<Host*>(expression)->operands[index] = (Expression*)operandExpr; -} -BinaryenIndex BinaryenHostAppendOperand(BinaryenExpressionRef expr, - BinaryenExpressionRef operandExpr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - assert(operandExpr); - auto& list = static_cast<Host*>(expression)->operands; - auto index = list.size(); - list.push_back((Expression*)operandExpr); - return index; -} -void BinaryenHostInsertOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index, - BinaryenExpressionRef operandExpr) { - auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - assert(operandExpr); - static_cast<Host*>(expression) - ->operands.insertAt(index, (Expression*)operandExpr); -} -BinaryenExpressionRef BinaryenHostRemoveOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index) { +void BinaryenMemoryGrowSetDelta(BinaryenExpressionRef expr, + BinaryenExpressionRef deltaExpr) { auto* expression = (Expression*)expr; - assert(expression->is<Host>()); - return static_cast<Host*>(expression)->operands.removeAt(index); + assert(expression->is<MemoryGrow>()); + assert(deltaExpr); + static_cast<MemoryGrow*>(expression)->delta = (Expression*)deltaExpr; } // Load int BinaryenLoadIsAtomic(BinaryenExpressionRef expr) { diff --git a/src/binaryen-c.h b/src/binaryen-c.h index c462bfc0f..f368ad122 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -142,7 +142,8 @@ BINARYEN_API BinaryenExpressionId BinaryenBinaryId(void); BINARYEN_API BinaryenExpressionId BinaryenSelectId(void); BINARYEN_API BinaryenExpressionId BinaryenDropId(void); BINARYEN_API BinaryenExpressionId BinaryenReturnId(void); -BINARYEN_API BinaryenExpressionId BinaryenHostId(void); +BINARYEN_API BinaryenExpressionId BinaryenMemorySizeId(void); +BINARYEN_API BinaryenExpressionId BinaryenMemoryGrowId(void); BINARYEN_API BinaryenExpressionId BinaryenNopId(void); BINARYEN_API BinaryenExpressionId BinaryenUnreachableId(void); BINARYEN_API BinaryenExpressionId BinaryenAtomicCmpxchgId(void); @@ -383,8 +384,6 @@ BINARYEN_API BinaryenOp BinaryenLtFloat64(void); BINARYEN_API BinaryenOp BinaryenLeFloat64(void); BINARYEN_API BinaryenOp BinaryenGtFloat64(void); BINARYEN_API BinaryenOp BinaryenGeFloat64(void); -BINARYEN_API BinaryenOp BinaryenMemorySize(void); -BINARYEN_API BinaryenOp BinaryenMemoryGrow(void); BINARYEN_API BinaryenOp BinaryenAtomicRMWAdd(void); BINARYEN_API BinaryenOp BinaryenAtomicRMWSub(void); BINARYEN_API BinaryenOp BinaryenAtomicRMWAnd(void); @@ -729,12 +728,9 @@ BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module, // Return: value can be NULL BINARYEN_API BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value); -// Host: name may be NULL -BINARYEN_API BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, - BinaryenOp op, - const char* name, - BinaryenExpressionRef* operands, - BinaryenIndex numOperands); +BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module); +BINARYEN_API BinaryenExpressionRef +BinaryenMemoryGrow(BinaryenModuleRef module, BinaryenExpressionRef delta); BINARYEN_API BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module); BINARYEN_API BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module); @@ -1153,43 +1149,14 @@ BinaryenGlobalSetGetValue(BinaryenExpressionRef expr); BINARYEN_API void BinaryenGlobalSetSetValue(BinaryenExpressionRef expr, BinaryenExpressionRef valueExpr); -// Host - -// Gets the operation being performed by a host expression. -BINARYEN_API BinaryenOp BinaryenHostGetOp(BinaryenExpressionRef expr); -// Sets the operation being performed by a host expression. -BINARYEN_API void BinaryenHostSetOp(BinaryenExpressionRef expr, BinaryenOp op); -// Gets the name operand, if any, of a host expression. -BINARYEN_API const char* BinaryenHostGetNameOperand(BinaryenExpressionRef expr); -// Sets the name operand, if any, of a host expression. -BINARYEN_API void BinaryenHostSetNameOperand(BinaryenExpressionRef expr, - const char* nameOperand); -// Gets the number of operands of a host expression. -BINARYEN_API BinaryenIndex -BinaryenHostGetNumOperands(BinaryenExpressionRef expr); -// Gets the operand at the specified index of a host expression. -BINARYEN_API BinaryenExpressionRef -BinaryenHostGetOperandAt(BinaryenExpressionRef expr, BinaryenIndex index); -// Sets the operand at the specified index of a host expression. -BINARYEN_API void BinaryenHostSetOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index, - BinaryenExpressionRef operandExpr); -// Appends an operand expression to a host expression, returning its insertion -// index. -BINARYEN_API BinaryenIndex BinaryenHostAppendOperand( - BinaryenExpressionRef expr, BinaryenExpressionRef operandExpr); -// Inserts an operand expression at the specified index of a host expression, -// moving existing operands including the one previously at that index one index -// up. -BINARYEN_API void -BinaryenHostInsertOperandAt(BinaryenExpressionRef expr, - BinaryenIndex index, - BinaryenExpressionRef operandExpr); -// Removes the operand expression at the specified index of a host expression, -// moving all subsequent operands one index down. Returns the operand -// expression. +// MemoryGrow + +// Gets the delta of a `memory.grow` expression. BINARYEN_API BinaryenExpressionRef -BinaryenHostRemoveOperandAt(BinaryenExpressionRef expr, BinaryenIndex index); +BinaryenMemoryGrowGetDelta(BinaryenExpressionRef expr); +// Sets the delta of a `memory.grow` expression. +BINARYEN_API void BinaryenMemoryGrowSetDelta(BinaryenExpressionRef expr, + BinaryenExpressionRef delta); // Load diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 6d9160c88..d14e5bbdc 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -2503,13 +2503,13 @@ switch (op[0]) { if (strcmp(op, "memory.fill") == 0) { return makeMemoryFill(s); } goto parse_error; case 'g': - if (strcmp(op, "memory.grow") == 0) { return makeHost(s, HostOp::MemoryGrow); } + if (strcmp(op, "memory.grow") == 0) { return makeMemoryGrow(s); } goto parse_error; case 'i': if (strcmp(op, "memory.init") == 0) { return makeMemoryInit(s); } goto parse_error; case 's': - if (strcmp(op, "memory.size") == 0) { return makeHost(s, HostOp::MemorySize); } + if (strcmp(op, "memory.size") == 0) { return makeMemorySize(s); } goto parse_error; default: goto parse_error; } diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp index d2f9611f9..37ba82e81 100644 --- a/src/ir/ExpressionAnalyzer.cpp +++ b/src/ir/ExpressionAnalyzer.cpp @@ -215,10 +215,8 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) { void visitSelect(Select* curr) {} void visitDrop(Drop* curr) {} void visitReturn(Return* curr) {} - void visitHost(Host* curr) { - visitor.visitInt(curr->op); - visitor.visitNonScopeName(curr->nameOperand); - } + void visitMemorySize(MemorySize* curr) {} + void visitMemoryGrow(MemoryGrow* curr) {} void visitRefNull(RefNull* curr) { visitor.visitType(curr->type); } void visitRefIsNull(RefIsNull* curr) {} void visitRefFunc(RefFunc* curr) { visitor.visitNonScopeName(curr->func); } diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp index 6f64ec77b..e1264e96e 100644 --- a/src/ir/ExpressionManipulator.cpp +++ b/src/ir/ExpressionManipulator.cpp @@ -218,14 +218,11 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) { Expression* visitReturn(Return* curr) { return builder.makeReturn(copy(curr->value)); } - Expression* visitHost(Host* curr) { - std::vector<Expression*> operands; - for (Index i = 0; i < curr->operands.size(); i++) { - operands.push_back(copy(curr->operands[i])); - } - auto* ret = - builder.makeHost(curr->op, curr->nameOperand, std::move(operands)); - return ret; + Expression* visitMemorySize(MemorySize* curr) { + return builder.makeMemorySize(); + } + Expression* visitMemoryGrow(MemoryGrow* curr) { + return builder.makeMemoryGrow(copy(curr->delta)); } Expression* visitRefNull(RefNull* curr) { return builder.makeRefNull(curr->type); diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 822fc5808..b6e2a1b59 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -119,7 +119,8 @@ void ReFinalize::visitBinary(Binary* curr) { curr->finalize(); } void ReFinalize::visitSelect(Select* curr) { curr->finalize(); } void ReFinalize::visitDrop(Drop* curr) { curr->finalize(); } void ReFinalize::visitReturn(Return* curr) { curr->finalize(); } -void ReFinalize::visitHost(Host* 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::visitRefIsNull(RefIsNull* curr) { curr->finalize(); } void ReFinalize::visitRefFunc(RefFunc* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index ea3e32909..056d51447 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -754,7 +754,8 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> { } Index visitDrop(Drop* curr) { return visit(curr->value); } Index visitReturn(Return* curr) { return maybeVisit(curr->value); } - Index visitHost(Host* curr) { return 100; } + Index visitMemorySize(MemorySize* curr) { return 1; } + Index visitMemoryGrow(MemoryGrow* curr) { return 100; } Index visitRefNull(RefNull* curr) { return 1; } Index visitRefIsNull(RefIsNull* curr) { return 1; } Index visitRefFunc(RefFunc* curr) { return 1; } diff --git a/src/ir/effects.h b/src/ir/effects.h index 9d6e90936..b973d7446 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -428,7 +428,8 @@ struct EffectAnalyzer implicitTrap = true; break; } - default: {} + default: { + } } } } @@ -446,17 +447,27 @@ struct EffectAnalyzer implicitTrap = true; break; } - default: {} + default: { + } } } } void visitSelect(Select* curr) {} void visitDrop(Drop* curr) {} void visitReturn(Return* curr) { branchesOut = true; } - void visitHost(Host* curr) { + void visitMemorySize(MemorySize* curr) { + // memory.size accesses the size of the memory, and thus can be modeled as + // reading memory + readsMemory = true; + // Atomics are sequentially consistent with memory.size. + isAtomic = true; + } + void visitMemoryGrow(MemoryGrow* curr) { calls = true; - // memory.grow modifies the set of valid addresses, and thus can be modeled - // as modifying memory + // memory.grow technically does a read-modify-write operation on the memory + // size in the successful case, modifying the set of valid addresses, and + // just a read operation in the failure case + readsMemory = true; writesMemory = true; // Atomics are also sequentially consistent with memory.grow. isAtomic = true; diff --git a/src/ir/utils.h b/src/ir/utils.h index 176699591..51fe4c9e7 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -145,7 +145,8 @@ struct ReFinalize void visitSelect(Select* curr); void visitDrop(Drop* curr); void visitReturn(Return* curr); - void visitHost(Host* curr); + void visitMemorySize(MemorySize* curr); + void visitMemoryGrow(MemoryGrow* curr); void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); @@ -213,7 +214,8 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> { void visitSelect(Select* curr) { curr->finalize(); } void visitDrop(Drop* curr) { curr->finalize(); } void visitReturn(Return* curr) { curr->finalize(); } - void visitHost(Host* curr) { curr->finalize(); } + void visitMemorySize(MemorySize* curr) { curr->finalize(); } + void visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); } void visitRefNull(RefNull* curr) { curr->finalize(); } void visitRefIsNull(RefIsNull* curr) { curr->finalize(); } void visitRefFunc(RefFunc* curr) { curr->finalize(); } diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 7f5467312..b02216509 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -65,7 +65,8 @@ function initializeConstants() { 'Select', 'Drop', 'Return', - 'Host', + 'MemorySize', + 'MemoryGrow', 'Nop', 'Unreachable', 'AtomicCmpxchg', @@ -265,8 +266,6 @@ function initializeConstants() { 'LeFloat64', 'GtFloat64', 'GeFloat64', - 'MemorySize', - 'MemoryGrow', 'AtomicRMWAdd', 'AtomicRMWSub', 'AtomicRMWAnd', @@ -599,10 +598,10 @@ function wrapModule(module, self = {}) { self['memory'] = { 'size'() { - return Module['_BinaryenHost'](module, Module['MemorySize']); + return Module['_BinaryenMemorySize'](module); }, 'grow'(value) { - return Module['_BinaryenHost'](module, Module['MemoryGrow'], null, i32sToStack([value]), 1); + return Module['_BinaryenMemoryGrow'](module, value); }, 'init'(segment, dest, offset, size) { return Module['_BinaryenMemoryInit'](module, segment, dest, offset, size); @@ -2092,9 +2091,6 @@ function wrapModule(module, self = {}) { self['return'] = function(value) { return Module['_BinaryenReturn'](module, value); }; - self['host'] = function(op, name, operands = []) { - return preserveStack(() => Module['_BinaryenHost'](module, op, strToStack(name), i32sToStack(operands), operands.length)); - }; self['nop'] = function() { return Module['_BinaryenNop'](module); }; @@ -2637,14 +2633,17 @@ Module['getExpressionInfo'] = function(expr) { 'id': id, 'type': type }; - case Module['HostId']: + case Module['MemorySizeId']: return { 'id': id, - 'type': type, - 'op': Module['_BinaryenHostGetOp'](expr), - 'nameOperand': UTF8ToString(Module['_BinaryenHostGetNameOperand'](expr)), - 'operands': getAllNested(expr, Module['_BinaryenHostGetNumOperands'], Module['_BinaryenHostGetOperandAt']) + 'type': type }; + case Module['MemoryGrowId']: + return { + 'id': id, + 'type': type, + 'delta': Module['_BinaryenMemoryGrowGetDelta'](expr) + } case Module['AtomicRMWId']: return { 'id': id, @@ -3479,63 +3478,15 @@ Module['GlobalSet'] = makeExpressionWrapper({ } }); -Module['Host'] = makeExpressionWrapper({ - 'getOp'(expr) { - return Module['_BinaryenHostGetOp'](expr); - }, - 'setOp'(expr, op) { - Module['_BinaryenHostSetOp'](expr, op); - }, - 'getNameOperand'(expr) { - const name = Module['_BinaryenHostGetNameOperand'](expr); - return name ? UTF8ToString(name) : null; - }, - 'setNameOperand'(expr, name) { - preserveStack(() => { Module['_BinaryenHostSetNameOperand'](expr, strToStack(name)) }); - }, - 'getNumOperands'(expr) { - return Module['_BinaryenHostGetNumOperands'](expr); - }, - 'getOperands'(expr) { - const numOperands = Module['_BinaryenHostGetNumOperands'](expr); - const operands = new Array(numOperands); - let index = 0; - while (index < numOperands) { - operands[index] = Module['_BinaryenHostGetOperandAt'](expr, index++); - } - return operands; - }, - 'setOperands'(expr, operands) { - const numOperands = operands.length; - let prevNumOperands = Module['_BinaryenHostGetNumOperands'](expr); - let index = 0; - while (index < numOperands) { - if (index < prevNumOperands) { - Module['_BinaryenHostSetOperandAt'](expr, index, operands[index]); - } else { - Module['_BinaryenHostAppendOperand'](expr, operands[index]); - } - ++index; - } - while (prevNumOperands > index) { - Module['_BinaryenHostRemoveOperandAt'](expr, --prevNumOperands); - } - }, - 'getOperandAt'(expr, index) { - return Module['_BinaryenHostGetOperandAt'](expr, index); - }, - 'setOperandAt'(expr, index, operandExpr) { - Module['_BinaryenHostSetOperandAt'](expr, index, operandExpr); - }, - 'appendOperand'(expr, operandExpr) { - return Module['_BinaryenHostAppendOperand'](expr, operandExpr); - }, - 'insertOperandAt'(expr, index, operandExpr) { - Module['_BinaryenHostInsertOperandAt'](expr, index, operandExpr); - }, - 'removeOperandAt'(expr, index) { - return Module['_BinaryenHostRemoveOperandAt'](expr, index); +Module['MemorySize'] = makeExpressionWrapper({}); + +Module['MemoryGrow'] = makeExpressionWrapper({ + 'getDelta'(expr) { + return Module['_BinaryenMemoryGrowGetDelta'](expr); }, + 'setDelta'(expr, deltaExpr) { + Module['_BinaryenMemoryGrowSetDelta'](expr, deltaExpr); + } }); Module['Load'] = makeExpressionWrapper({ diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp index 9e2e194cb..4215de3f8 100644 --- a/src/passes/DeadCodeElimination.cpp +++ b/src/passes/DeadCodeElimination.cpp @@ -315,8 +315,10 @@ struct DeadCodeElimination DELEGATE(Drop); case Expression::Id::ReturnId: DELEGATE(Return); - case Expression::Id::HostId: - DELEGATE(Host); + case Expression::Id::MemorySizeId: + DELEGATE(MemorySize); + case Expression::Id::MemoryGrowId: + DELEGATE(MemoryGrow); case Expression::Id::NopId: DELEGATE(Nop); case Expression::Id::UnreachableId: @@ -519,7 +521,11 @@ struct DeadCodeElimination blockifyReachableOperands({curr->value}, curr->type); } - void visitHost(Host* curr) { handleCall(curr); } + void visitMemorySize(MemorySize* curr) {} + + void visitMemoryGrow(MemoryGrow* curr) { + blockifyReachableOperands({curr->delta}, curr->type); + } void visitFunction(Function* curr) { assert(reachableBreaks.size() == 0); } }; diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp index 1a1e87502..eac7fb7f0 100644 --- a/src/passes/MemoryPacking.cpp +++ b/src/passes/MemoryPacking.cpp @@ -77,9 +77,8 @@ const size_t DATA_DROP_SIZE = 3; namespace { Expression* makeShiftedMemorySize(Builder& builder) { - return builder.makeBinary(ShlInt32, - builder.makeHost(MemorySize, Name(), {}), - builder.makeConst(int32_t(16))); + return builder.makeBinary( + ShlInt32, builder.makeMemorySize(), builder.makeConst(int32_t(16))); } } // anonymous namespace diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 15ab97098..916615e07 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1430,16 +1430,8 @@ struct PrintExpressionContents } void visitDrop(Drop* curr) { printMedium(o, "drop"); } void visitReturn(Return* curr) { printMedium(o, "return"); } - void visitHost(Host* curr) { - switch (curr->op) { - case MemorySize: - printMedium(o, "memory.size"); - break; - case MemoryGrow: - printMedium(o, "memory.grow"); - break; - } - } + void visitMemorySize(MemorySize* curr) { printMedium(o, "memory.size"); } + void visitMemoryGrow(MemoryGrow* curr) { printMedium(o, "memory.grow"); } void visitRefNull(RefNull* curr) { printMedium(o, "ref.null "); o << curr->type.getHeapType(); @@ -1577,7 +1569,9 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { o << ')'; } void printFullLine(Expression* expression) { - !minify && doIndent(o, indent); + if (!minify) { + doIndent(o, indent); + } if (full) { o << "[" << expression->type << "] "; } @@ -1945,20 +1939,17 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { printFullLine(curr->value); decIndent(); } - void visitHost(Host* curr) { + void visitMemorySize(MemorySize* curr) { o << '('; PrintExpressionContents(currFunction, o).visit(curr); - switch (curr->op) { - case MemoryGrow: { - incIndent(); - printFullLine(curr->operands[0]); - decIndent(); - break; - } - case MemorySize: { - o << ')'; - } - } + o << ')'; + } + void visitMemoryGrow(MemoryGrow* curr) { + o << '('; + PrintExpressionContents(currFunction, o).visit(curr); + incIndent(); + printFullLine(curr->delta); + decIndent(); } void visitRefNull(RefNull* curr) { o << '('; diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 21cbc5e5b..3795022c2 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -111,11 +111,8 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> { void visitDataDrop(DataDrop* curr) { usesMemory = true; } void visitMemoryCopy(MemoryCopy* curr) { usesMemory = true; } void visitMemoryFill(MemoryFill* curr) { usesMemory = true; } - void visitHost(Host* curr) { - if (curr->op == MemorySize || curr->op == MemoryGrow) { - usesMemory = true; - } - } + void visitMemorySize(MemorySize* curr) { usesMemory = true; } + void visitMemoryGrow(MemoryGrow* curr) { usesMemory = true; } void visitRefFunc(RefFunc* curr) { if (reachable.count( ModuleElement(ModuleElementKind::Function, curr->func)) == 0) { diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index 94537619c..618a198e5 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -92,7 +92,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { case Expression::Id::StoreId: case Expression::Id::ReturnId: case Expression::Id::GlobalSetId: - case Expression::Id::HostId: + case Expression::Id::MemorySizeId: + case Expression::Id::MemoryGrowId: case Expression::Id::UnreachableId: return curr; // always needed diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 77f53fcd2..da2378993 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1437,7 +1437,8 @@ public: bool maybeVisitMemoryFill(Expression*& out, uint32_t code); void visitSelect(Select* curr, uint8_t code); void visitReturn(Return* curr); - bool maybeVisitHost(Expression*& out, uint8_t code); + void visitMemorySize(MemorySize* curr); + void visitMemoryGrow(MemoryGrow* curr); void visitNop(Nop* curr); void visitUnreachable(Unreachable* curr); void visitDrop(Drop* curr); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 6c1923482..762d89dbe 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -519,12 +519,14 @@ public: ret->value = value; return ret; } - Host* - makeHost(HostOp op, Name nameOperand, std::vector<Expression*>&& operands) { - auto* ret = allocator.alloc<Host>(); - ret->op = op; - ret->nameOperand = nameOperand; - ret->operands.set(operands); + MemorySize* makeMemorySize() { + auto* ret = allocator.alloc<MemorySize>(); + ret->finalize(); + return ret; + } + MemoryGrow* makeMemoryGrow(Expression* delta) { + auto* ret = allocator.alloc<MemoryGrow>(); + ret->delta = delta; ret->finalize(); return ret; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 361545a2c..8fc595034 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1226,7 +1226,8 @@ public: Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE("unimp"); } Flow visitLoad(Load* curr) { WASM_UNREACHABLE("unimp"); } Flow visitStore(Store* curr) { WASM_UNREACHABLE("unimp"); } - Flow visitHost(Host* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitMemorySize(MemorySize* curr) { WASM_UNREACHABLE("unimp"); } + Flow visitMemoryGrow(MemoryGrow* curr) { WASM_UNREACHABLE("unimp"); } Flow visitMemoryInit(MemoryInit* curr) { WASM_UNREACHABLE("unimp"); } Flow visitDataDrop(DataDrop* curr) { WASM_UNREACHABLE("unimp"); } Flow visitMemoryCopy(MemoryCopy* curr) { WASM_UNREACHABLE("unimp"); } @@ -1491,8 +1492,12 @@ public: NOTE_ENTER("Store"); return Flow(NONCONSTANT_FLOW); } - Flow visitHost(Host* curr) { - NOTE_ENTER("Host"); + Flow visitMemorySize(MemorySize* curr) { + NOTE_ENTER("MemorySize"); + return Flow(NONCONSTANT_FLOW); + } + Flow visitMemoryGrow(MemoryGrow* curr) { + NOTE_ENTER("MemoryGrow"); return Flow(NONCONSTANT_FLOW); } Flow visitMemoryInit(MemoryInit* curr) { @@ -2288,37 +2293,33 @@ private: return Literal(std::array<Literal, 2>{{val, zero}}); } } - Flow visitHost(Host* curr) { - NOTE_ENTER("Host"); - switch (curr->op) { - case MemorySize: - return Literal(int32_t(instance.memorySize)); - case MemoryGrow: { - auto fail = Literal(int32_t(-1)); - Flow flow = this->visit(curr->operands[0]); - if (flow.breaking()) { - return flow; - } - int32_t ret = instance.memorySize; - uint32_t delta = flow.getSingleValue().geti32(); - if (delta > uint32_t(-1) / Memory::kPageSize) { - return fail; - } - if (instance.memorySize >= uint32_t(-1) - delta) { - return fail; - } - uint32_t newSize = instance.memorySize + delta; - if (newSize > instance.wasm.memory.max) { - return fail; - } - instance.externalInterface->growMemory(instance.memorySize * - Memory::kPageSize, - newSize * Memory::kPageSize); - instance.memorySize = newSize; - return Literal(int32_t(ret)); - } + Flow visitMemorySize(MemorySize* curr) { + NOTE_ENTER("MemorySize"); + return Literal(int32_t(instance.memorySize)); + } + Flow visitMemoryGrow(MemoryGrow* curr) { + NOTE_ENTER("MemoryGrow"); + auto fail = Literal(int32_t(-1)); + Flow flow = this->visit(curr->delta); + if (flow.breaking()) { + return flow; } - WASM_UNREACHABLE("invalid op"); + int32_t ret = instance.memorySize; + uint32_t delta = flow.getSingleValue().geti32(); + if (delta > uint32_t(-1) / Memory::kPageSize) { + return fail; + } + if (instance.memorySize >= uint32_t(-1) - delta) { + return fail; + } + uint32_t newSize = instance.memorySize + delta; + if (newSize > instance.wasm.memory.max) { + return fail; + } + instance.externalInterface->growMemory( + instance.memorySize * Memory::kPageSize, newSize * Memory::kPageSize); + instance.memorySize = newSize; + return Literal(int32_t(ret)); } Flow visitMemoryInit(MemoryInit* curr) { NOTE_ENTER("MemoryInit"); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 85ca217e7..68baf7b08 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -183,7 +183,8 @@ private: Expression* makeUnary(Element& s, UnaryOp op); Expression* makeSelect(Element& s); Expression* makeDrop(Element& s); - Expression* makeHost(Element& s, HostOp op); + Expression* makeMemorySize(Element& s); + Expression* makeMemoryGrow(Element& s); Index getLocalIndex(Element& s); Expression* makeLocalGet(Element& s); Expression* makeLocalTee(Element& s); diff --git a/src/wasm-stack.h b/src/wasm-stack.h index ed9245d4f..6a926eddf 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -132,7 +132,8 @@ public: void visitBinary(Binary* curr); void visitSelect(Select* curr); void visitReturn(Return* curr); - void visitHost(Host* curr); + void visitMemorySize(MemorySize* curr); + void visitMemoryGrow(MemoryGrow* curr); void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index fc6b1cbb8..94997caf1 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -71,7 +71,8 @@ template<typename SubType, typename ReturnType = void> struct Visitor { ReturnType visitSelect(Select* curr) { return ReturnType(); } ReturnType visitDrop(Drop* curr) { return ReturnType(); } ReturnType visitReturn(Return* curr) { return ReturnType(); } - ReturnType visitHost(Host* curr) { return ReturnType(); } + ReturnType visitMemorySize(MemorySize* curr) { return ReturnType(); } + ReturnType visitMemoryGrow(MemoryGrow* curr) { return ReturnType(); } ReturnType visitRefNull(RefNull* curr) { return ReturnType(); } ReturnType visitRefIsNull(RefIsNull* curr) { return ReturnType(); } ReturnType visitRefFunc(RefFunc* curr) { return ReturnType(); } @@ -169,8 +170,10 @@ template<typename SubType, typename ReturnType = void> struct Visitor { DELEGATE(Drop); case Expression::Id::ReturnId: DELEGATE(Return); - case Expression::Id::HostId: - DELEGATE(Host); + case Expression::Id::MemorySizeId: + DELEGATE(MemorySize); + case Expression::Id::MemoryGrowId: + DELEGATE(MemoryGrow); case Expression::Id::RefNullId: DELEGATE(RefNull); case Expression::Id::RefIsNullId: @@ -252,7 +255,8 @@ struct OverriddenVisitor { UNIMPLEMENTED(Select); UNIMPLEMENTED(Drop); UNIMPLEMENTED(Return); - UNIMPLEMENTED(Host); + UNIMPLEMENTED(MemorySize); + UNIMPLEMENTED(MemoryGrow); UNIMPLEMENTED(RefNull); UNIMPLEMENTED(RefIsNull); UNIMPLEMENTED(RefFunc); @@ -351,8 +355,10 @@ struct OverriddenVisitor { DELEGATE(Drop); case Expression::Id::ReturnId: DELEGATE(Return); - case Expression::Id::HostId: - DELEGATE(Host); + case Expression::Id::MemorySizeId: + DELEGATE(MemorySize); + case Expression::Id::MemoryGrowId: + DELEGATE(MemoryGrow); case Expression::Id::RefNullId: DELEGATE(RefNull); case Expression::Id::RefIsNullId: @@ -497,7 +503,10 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> { ReturnType visitReturn(Return* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } - ReturnType visitHost(Host* curr) { + ReturnType visitMemorySize(MemorySize* curr) { + return static_cast<SubType*>(this)->visitExpression(curr); + } + ReturnType visitMemoryGrow(MemoryGrow* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } ReturnType visitRefNull(RefNull* curr) { @@ -811,8 +820,11 @@ struct Walker : public VisitorType { static void doVisitReturn(SubType* self, Expression** currp) { self->visitReturn((*currp)->cast<Return>()); } - static void doVisitHost(SubType* self, Expression** currp) { - self->visitHost((*currp)->cast<Host>()); + static void doVisitMemorySize(SubType* self, Expression** currp) { + self->visitMemorySize((*currp)->cast<MemorySize>()); + } + static void doVisitMemoryGrow(SubType* self, Expression** currp) { + self->visitMemoryGrow((*currp)->cast<MemoryGrow>()); } static void doVisitRefNull(SubType* self, Expression** currp) { self->visitRefNull((*currp)->cast<RefNull>()); @@ -1076,14 +1088,13 @@ struct PostWalker : public Walker<SubType, VisitorType> { self->maybePushTask(SubType::scan, &curr->cast<Return>()->value); break; } - case Expression::Id::HostId: { - self->pushTask(SubType::doVisitHost, currp); - auto& list = curr->cast<Host>()->operands; - for (int i = int(list.size()) - 1; i >= 0; i--) { - self->pushTask(SubType::scan, &list[i]); - } + case Expression::Id::MemorySizeId: + self->pushTask(SubType::doVisitMemorySize, currp); + break; + case Expression::Id::MemoryGrowId: + self->pushTask(SubType::doVisitMemoryGrow, currp); + self->pushTask(SubType::scan, &curr->cast<MemoryGrow>()->delta); break; - } case Expression::Id::RefNullId: { self->pushTask(SubType::doVisitRefNull, currp); break; @@ -1210,7 +1221,8 @@ struct ControlFlowWalker : public PostWalker<SubType, VisitorType> { self->pushTask(SubType::doPostVisitControlFlow, currp); break; } - default: {} + default: { + } } PostWalker<SubType, VisitorType>::scan(self, currp); @@ -1223,7 +1235,8 @@ struct ControlFlowWalker : public PostWalker<SubType, VisitorType> { self->pushTask(SubType::doPreVisitControlFlow, currp); break; } - default: {} + default: { + } } } }; diff --git a/src/wasm.h b/src/wasm.h index c5db2fbd3..419e02875 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -434,8 +434,6 @@ enum BinaryOp { InvalidBinary }; -enum HostOp { MemorySize, MemoryGrow }; - enum AtomicRMWOp { Add, Sub, And, Or, Xor, Xchg }; enum SIMDExtractOp { @@ -534,7 +532,8 @@ public: SelectId, DropId, ReturnId, - HostId, + MemorySizeId, + MemoryGrowId, NopId, UnreachableId, AtomicRMWId, @@ -1066,13 +1065,20 @@ public: Expression* value = nullptr; }; -class Host : public SpecificExpression<Expression::HostId> { +class MemorySize : public SpecificExpression<Expression::MemorySizeId> { public: - Host(MixedArena& allocator) : operands(allocator) {} + MemorySize() { type = Type::i32; } + MemorySize(MixedArena& allocator) : MemorySize() {} - HostOp op; - Name nameOperand; - ExpressionList operands; + void finalize(); +}; + +class MemoryGrow : public SpecificExpression<Expression::MemoryGrowId> { +public: + MemoryGrow() { type = Type::i32; } + MemoryGrow(MixedArena& allocator) : MemoryGrow() {} + + Expression* delta = nullptr; void finalize(); }; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 2910bb383..e958dca6e 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2452,6 +2452,14 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { case BinaryConsts::BrOnExn: visitBrOnExn((curr = allocator.alloc<BrOnExn>())->cast<BrOnExn>()); break; + case BinaryConsts::MemorySize: + visitMemorySize( + (curr = allocator.alloc<MemorySize>())->cast<MemorySize>()); + break; + case BinaryConsts::MemoryGrow: + visitMemoryGrow( + (curr = allocator.alloc<MemoryGrow>())->cast<MemoryGrow>()); + break; case BinaryConsts::AtomicPrefix: { code = static_cast<uint8_t>(getU32LEB()); if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) { @@ -2551,9 +2559,6 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitStore(curr, code, /*isAtomic=*/false)) { break; } - if (maybeVisitHost(curr, code)) { - break; - } throwError("bad node code " + std::to_string(code)); break; } @@ -4763,32 +4768,23 @@ void WasmBinaryBuilder::visitReturn(Return* curr) { curr->finalize(); } -bool WasmBinaryBuilder::maybeVisitHost(Expression*& out, uint8_t code) { - Host* curr; - switch (code) { - case BinaryConsts::MemorySize: { - curr = allocator.alloc<Host>(); - curr->op = MemorySize; - break; - } - case BinaryConsts::MemoryGrow: { - curr = allocator.alloc<Host>(); - curr->op = MemoryGrow; - curr->operands.resize(1); - curr->operands[0] = popNonVoidExpression(); - break; - } - default: - return false; +void WasmBinaryBuilder::visitMemorySize(MemorySize* curr) { + BYN_TRACE("zz node: MemorySize\n"); + auto reserved = getU32LEB(); + if (reserved != 0) { + throwError("Invalid reserved field on memory.size"); } - BYN_TRACE("zz node: Host\n"); + curr->finalize(); +} + +void WasmBinaryBuilder::visitMemoryGrow(MemoryGrow* curr) { + BYN_TRACE("zz node: MemoryGrow\n"); + curr->delta = popNonVoidExpression(); auto reserved = getU32LEB(); if (reserved != 0) { - throwError("Invalid reserved field on memory.grow/memory.size"); + throwError("Invalid reserved field on memory.grow"); } curr->finalize(); - out = curr; - return true; } void WasmBinaryBuilder::visitNop(Nop* curr) { BYN_TRACE("zz node: Nop\n"); } diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index e41d0df48..a0f0ade9d 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -122,7 +122,7 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() { Function* growFunction = builder.makeFunction(name, std::move(params), Type::i32, {}); growFunction->body = - builder.makeHost(MemoryGrow, Name(), {builder.makeLocalGet(0, Type::i32)}); + builder.makeMemoryGrow(builder.makeLocalGet(0, Type::i32)); addExportedFunction(wasm, growFunction); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 97da80fea..2883519f2 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1021,19 +1021,15 @@ Expression* SExpressionWasmBuilder::makeDrop(Element& s) { return ret; } -Expression* SExpressionWasmBuilder::makeHost(Element& s, HostOp op) { - auto ret = allocator.alloc<Host>(); - ret->op = op; - parseCallOperands(s, 1, s.size(), ret); - if (ret->op == HostOp::MemoryGrow) { - if (ret->operands.size() != 1) { - throw ParseException("memory.grow needs one operand", s.line, s.col); - } - } else { - if (ret->operands.size() != 0) { - throw ParseException("host needs zero operands", s.line, s.col); - } - } +Expression* SExpressionWasmBuilder::makeMemorySize(Element& s) { + auto ret = allocator.alloc<MemorySize>(); + ret->finalize(); + return ret; +} + +Expression* SExpressionWasmBuilder::makeMemoryGrow(Element& s) { + auto ret = allocator.alloc<MemoryGrow>(); + ret->delta = parseExpression(s[1]); ret->finalize(); return ret; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 64622e814..edfdf31d1 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -1671,17 +1671,13 @@ void BinaryInstWriter::visitReturn(Return* curr) { o << int8_t(BinaryConsts::Return); } -void BinaryInstWriter::visitHost(Host* curr) { - switch (curr->op) { - case MemorySize: { - o << int8_t(BinaryConsts::MemorySize); - break; - } - case MemoryGrow: { - o << int8_t(BinaryConsts::MemoryGrow); - break; - } - } +void BinaryInstWriter::visitMemorySize(MemorySize* curr) { + o << int8_t(BinaryConsts::MemorySize); + o << U32LEB(0); // Reserved flags field +} + +void BinaryInstWriter::visitMemoryGrow(MemoryGrow* curr) { + o << int8_t(BinaryConsts::MemoryGrow); o << U32LEB(0); // Reserved flags field } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 15fb66926..c141fdd6f 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -326,7 +326,8 @@ public: void visitSelect(Select* curr); void visitDrop(Drop* curr); void visitReturn(Return* curr); - void visitHost(Host* curr); + void visitMemorySize(MemorySize* curr); + void visitMemoryGrow(MemoryGrow* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); void visitTry(Try* curr); @@ -1897,24 +1898,18 @@ void FunctionValidator::visitReturn(Return* curr) { returnTypes.insert(curr->value ? curr->value->type : Type::none); } -void FunctionValidator::visitHost(Host* curr) { +void FunctionValidator::visitMemorySize(MemorySize* curr) { shouldBeTrue( getModule()->memory.exists, curr, "Memory operations require a memory"); - switch (curr->op) { - case MemoryGrow: { - shouldBeEqual(curr->operands.size(), - size_t(1), - curr, - "memory.grow must have 1 operand"); - shouldBeEqualOrFirstIsUnreachable(curr->operands[0]->type, - Type(Type::i32), - curr, - "memory.grow must have i32 operand"); - break; - } - case MemorySize: - break; - } +} + +void FunctionValidator::visitMemoryGrow(MemoryGrow* curr) { + shouldBeTrue( + getModule()->memory.exists, curr, "Memory operations require a memory"); + shouldBeEqualOrFirstIsUnreachable(curr->delta->type, + Type(Type::i32), + curr, + "memory.grow must have i32 operand"); } void FunctionValidator::visitRefIsNull(RefIsNull* curr) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 9d43a33b1..d3c0b46e8 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -145,8 +145,10 @@ const char* getExpressionName(Expression* curr) { return "drop"; case Expression::Id::ReturnId: return "return"; - case Expression::Id::HostId: - return "host"; + case Expression::Id::MemorySizeId: + return "memory.size"; + case Expression::Id::MemoryGrowId: + return "memory.grow"; case Expression::Id::NopId: return "nop"; case Expression::Id::UnreachableId: @@ -879,21 +881,13 @@ void Drop::finalize() { } } -void Host::finalize() { - switch (op) { - case MemorySize: { - type = Type::i32; - break; - } - case MemoryGrow: { - // if the single operand is not reachable, so are we - if (operands[0]->type == Type::unreachable) { - type = Type::unreachable; - } else { - type = Type::i32; - } - break; - } +void MemorySize::finalize() { type = Type::i32; } + +void MemoryGrow::finalize() { + if (delta->type == Type::unreachable) { + type = Type::unreachable; + } else { + type = Type::i32; } } diff --git a/src/wasm2js.h b/src/wasm2js.h index ac0268e5b..8418d5b15 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -1321,8 +1321,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, !FindAll<Call>(curr->value).list.empty() || !FindAll<CallIndirect>(curr->ptr).list.empty() || !FindAll<CallIndirect>(curr->value).list.empty() || - !FindAll<Host>(curr->ptr).list.empty() || - !FindAll<Host>(curr->value).list.empty()) { + !FindAll<MemoryGrow>(curr->ptr).list.empty() || + !FindAll<MemoryGrow>(curr->value).list.empty()) { Ref ret; ScopedTemp ptr(Type::i32, parent, func); sequenceAppend(ret, visitAndAssign(curr->ptr, ptr)); @@ -1842,21 +1842,20 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, return ValueBuilder::makeReturn(val); } - Ref visitHost(Host* curr) { - if (curr->op == HostOp::MemoryGrow) { - if (module->memory.exists && - module->memory.max > module->memory.initial) { - return ValueBuilder::makeCall( - WASM_MEMORY_GROW, - makeAsmCoercion(visit(curr->operands[0], EXPRESSION_RESULT), - wasmToAsmType(curr->operands[0]->type))); - } else { - return ValueBuilder::makeCall(ABORT_FUNC); - } - } else if (curr->op == HostOp::MemorySize) { - return ValueBuilder::makeCall(WASM_MEMORY_SIZE); + Ref visitMemorySize(MemorySize* curr) { + return ValueBuilder::makeCall(WASM_MEMORY_SIZE); + } + + Ref visitMemoryGrow(MemoryGrow* curr) { + if (module->memory.exists && + module->memory.max > module->memory.initial) { + return ValueBuilder::makeCall( + WASM_MEMORY_GROW, + makeAsmCoercion(visit(curr->delta, EXPRESSION_RESULT), + wasmToAsmType(curr->delta->type))); + } else { + return ValueBuilder::makeCall(ABORT_FUNC); } - WASM_UNREACHABLE("unexpected expr type"); // TODO } Ref visitNop(Nop* curr) { return ValueBuilder::makeToplevel(); } diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index 21eb9a70d..ab545aac9 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -28,7 +28,7 @@ ) ) -getExpressionInfo(throw) = {"id":43,"type":1,"event":"e"} -getExpressionInfo(br_on_exn) = {"id":45,"type":9,"name":"l","event":"e"} -getExpressionInfo(rethrow) = {"id":44,"type":1} -getExpressionInfo(try) = {"id":42,"type":0} +getExpressionInfo(throw) = {"id":44,"type":1,"event":"e"} +getExpressionInfo(br_on_exn) = {"id":46,"type":9,"name":"l","event":"e"} +getExpressionInfo(rethrow) = {"id":45,"type":1} +getExpressionInfo(try) = {"id":43,"type":0} diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index a0f3e6d4b..a9a0ab982 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -465,39 +465,55 @@ console.log("# GlobalSet"); module.dispose(); })(); -console.log("# Host"); -(function testHost() { +console.log("# MemorySize"); +(function testMemorySize() { const module = new binaryen.Module(); - var op = binaryen.Operations.MemorySize; - var nameOp = null; - var operands = []; - const theHost = binaryen.Host(module.memory.size()); - assert(theHost instanceof binaryen.Host); - assert(theHost instanceof binaryen.Expression); - assert(theHost.op === op); - assert(theHost.nameOperand === nameOp); - assertDeepEqual(theHost.operands, operands); - assert(theHost.type === binaryen.i32); - - theHost.op = op = binaryen.Operations.MemoryGrow; - assert(theHost.op === op); - theHost.nameOperand = nameOp = "a"; - assert(theHost.nameOperand === nameOp); - theHost.nameOperand = null; - theHost.operands = operands = [ - module.i32.const(1) - ]; - assertDeepEqual(theHost.operands, operands); - theHost.type = binaryen.f64; - theHost.finalize(); - assert(theHost.type === binaryen.i32); + var type = binaryen.i32; + const theMemorySize = binaryen.MemorySize(module.memory.size()); + assert(theMemorySize instanceof binaryen.MemorySize); + assert(theMemorySize instanceof binaryen.Expression); + assert(theMemorySize.type === type); + + theMemorySize.type = type = binaryen.f64; + assert(theMemorySize.type === type); + theMemorySize.finalize(); + assert(theMemorySize.type === binaryen.i32); + + console.log(theMemorySize.toText()); + assert( + theMemorySize.toText() + == + "(memory.size)\n" + ); - console.log(theHost.toText()); + module.dispose(); +})(); + +console.log("# MemoryGrow"); +(function testMemoryGrow() { + const module = new binaryen.Module(); + + var type = binaryen.i32; + var delta = module.i32.const(1); + const theMemoryGrow = binaryen.MemoryGrow(module.memory.grow(delta)); + assert(theMemoryGrow instanceof binaryen.MemoryGrow); + assert(theMemoryGrow instanceof binaryen.Expression); + assert(theMemoryGrow.delta === delta); + assert(theMemoryGrow.type === type); + + theMemoryGrow.delta = delta = module.i32.const(2); + assert(theMemoryGrow.delta === delta); + theMemoryGrow.type = type = binaryen.f64; + assert(theMemoryGrow.type === type); + theMemoryGrow.finalize(); + assert(theMemoryGrow.type === binaryen.i32); + + console.log(theMemoryGrow.toText()); assert( - theHost.toText() + theMemoryGrow.toText() == - "(memory.grow\n (i32.const 1)\n)\n" + "(memory.grow\n (i32.const 2)\n)\n" ); module.dispose(); diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt index 239498b1f..a8946875a 100644 --- a/test/binaryen.js/expressions.js.txt +++ b/test/binaryen.js/expressions.js.txt @@ -64,9 +64,12 @@ (f64.const 3) ) -# Host +# MemorySize +(memory.size) + +# MemoryGrow (memory.grow - (i32.const 1) + (i32.const 2) ) # Load diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 5a3da277e..d985b39aa 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -131,7 +131,8 @@ function test_ids() { console.log("SelectId: " + binaryen.SelectId); console.log("DropId: " + binaryen.DropId); console.log("ReturnId: " + binaryen.ReturnId); - console.log("HostId: " + binaryen.HostId); + console.log("MemorySizeId: " + binaryen.MemorySizeId); + console.log("MemoryGrowId: " + binaryen.MemoryGrowId); console.log("NopId: " + binaryen.NopId); console.log("UnreachableId: " + binaryen.UnreachableId); console.log("AtomicCmpxchgId: " + binaryen.AtomicCmpxchgId); @@ -572,7 +573,12 @@ function test_core() { module.externref.pop(), module.funcref.pop(), module.exnref.pop(), - // TODO: Host + + // Memory + module.memory.size(), + module.memory.grow(makeInt32(0)), + + // Other module.nop(), module.unreachable(), ]; diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 2f75640d1..54052a597 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -57,28 +57,29 @@ BinaryId: 16 SelectId: 17 DropId: 18 ReturnId: 19 -HostId: 20 -NopId: 21 -UnreachableId: 22 -AtomicCmpxchgId: 24 -AtomicRMWId: 23 -AtomicWaitId: 25 -AtomicNotifyId: 26 -SIMDExtractId: 28 -SIMDReplaceId: 29 -SIMDShuffleId: 30 -SIMDTernaryId: 31 -SIMDShiftId: 32 -SIMDLoadId: 33 -MemoryInitId: 34 -DataDropId: 35 -MemoryCopyId: 36 -MemoryFillId: 37 -TryId: 42 -ThrowId: 43 -RethrowId: 44 -BrOnExnId: 45 -PopId: 38 +MemorySizeId: 20 +MemoryGrowId: 21 +NopId: 22 +UnreachableId: 23 +AtomicCmpxchgId: 25 +AtomicRMWId: 24 +AtomicWaitId: 26 +AtomicNotifyId: 27 +SIMDExtractId: 29 +SIMDReplaceId: 30 +SIMDShuffleId: 31 +SIMDTernaryId: 32 +SIMDShiftId: 33 +SIMDLoadId: 34 +MemoryInitId: 35 +DataDropId: 36 +MemoryCopyId: 37 +MemoryFillId: 38 +TryId: 43 +ThrowId: 44 +RethrowId: 45 +BrOnExnId: 46 +PopId: 39 getExpressionInfo={"id":15,"type":4,"op":6} (f32.neg (f32.const -33.61199951171875) @@ -1919,6 +1920,14 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (drop (pop exnref) ) + (drop + (memory.size) + ) + (drop + (memory.grow + (i32.const 0) + ) + ) (nop) (unreachable) ) @@ -3759,6 +3768,14 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (drop (pop exnref) ) + (drop + (memory.size) + ) + (drop + (memory.grow + (i32.const 0) + ) + ) (nop) (unreachable) ) @@ -4336,5 +4353,5 @@ sizeof Literal: 24 ) ) -getExpressionInfo(memory.grow)={"id":20,"type":2,"op":1,"nameOperand":"","operands":[1]} +getExpressionInfo(memory.grow)={"id":21,"type":2,"delta":1} getExpressionInfo(switch)={"id":5,"type":1,"names":["label"],"defaultName":"label","condition":0,"value":0} diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index d4072476e..f619e6db5 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -756,8 +756,10 @@ void test_core() { BinaryenPop(module, BinaryenTypeExternref()), BinaryenPop(module, BinaryenTypeExnref()), BinaryenPop(module, iIfF), - - // TODO: Host + // Memory + BinaryenMemorySize(module), + BinaryenMemoryGrow(module, makeInt32(module, 0)), + // Other BinaryenNop(module), BinaryenUnreachable(module), }; diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index b891bf6ce..d92009c35 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -1857,6 +1857,14 @@ BinaryenFeatureAll: 2047 (drop (pop i32 i64 f32 f64) ) + (drop + (memory.size) + ) + (drop + (memory.grow + (i32.const 0) + ) + ) (nop) (unreachable) ) |