diff options
-rw-r--r-- | src/binaryen-c.cpp | 52 | ||||
-rw-r--r-- | src/binaryen-c.h | 20 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 26 | ||||
-rw-r--r-- | src/wasm-builder.h | 58 | ||||
-rw-r--r-- | test/binaryen.js/exception-handling.js | 40 | ||||
-rw-r--r-- | test/binaryen.js/exception-handling.js.txt | 18 | ||||
-rw-r--r-- | test/binaryen.js/expressions.js | 10 | ||||
-rw-r--r-- | test/binaryen.js/expressions.js.txt | 7 | ||||
-rw-r--r-- | test/binaryen.js/kitchen-sink.js | 4 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.c | 33 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.txt | 15 |
11 files changed, 250 insertions, 33 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 1015e41c0..f4d93afa1 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1210,21 +1210,29 @@ BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module, } BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, + const char* name, BinaryenExpressionRef body, - const char** catchEvents_, + const char** catchEvents, BinaryenIndex numCatchEvents, - BinaryenExpressionRef* catchBodies_, - BinaryenIndex numCatchBodies) { - std::vector<Name> catchEvents; - std::vector<Expression*> catchBodies; + BinaryenExpressionRef* catchBodies, + BinaryenIndex numCatchBodies, + const char* delegateTarget) { + auto* ret = ((Module*)module)->allocator.alloc<Try>(); + if (name) { + ret->name = name; + } + ret->body = (Expression*)body; for (BinaryenIndex i = 0; i < numCatchEvents; i++) { - catchEvents.push_back(catchEvents_[i]); + ret->catchEvents.push_back(catchEvents[i]); } for (BinaryenIndex i = 0; i < numCatchBodies; i++) { - catchBodies.push_back((Expression*)catchBodies_[i]); + ret->catchBodies.push_back((Expression*)catchBodies[i]); } - return static_cast<Expression*>( - Builder(*(Module*)module).makeTry(body, catchEvents, catchBodies)); + if (delegateTarget) { + ret->delegateTarget = delegateTarget; + } + ret->finalize(); + return static_cast<Expression*>(ret); } BinaryenExpressionRef BinaryenThrow(BinaryenModuleRef module, @@ -2765,6 +2773,16 @@ void BinaryenRefEqSetRight(BinaryenExpressionRef expr, static_cast<RefEq*>(expression)->right = (Expression*)right; } // Try +const char* BinaryenTryGetName(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<Try>()); + return static_cast<Try*>(expression)->name.c_str(); +} +void BinaryenTrySetName(BinaryenExpressionRef expr, const char* name) { + auto* expression = (Expression*)expr; + assert(expression->is<Try>()); + static_cast<Try*>(expression)->name = name; +} BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; assert(expression->is<Try>()); @@ -2873,6 +2891,22 @@ int BinaryenTryHasCatchAll(BinaryenExpressionRef expr) { assert(expression->is<Try>()); return static_cast<Try*>(expression)->hasCatchAll(); } +const char* BinaryenTryGetDelegateTarget(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<Try>()); + return static_cast<Try*>(expression)->delegateTarget.c_str(); +} +void BinaryenTrySetDelegateTarget(BinaryenExpressionRef expr, + const char* delegateTarget) { + auto* expression = (Expression*)expr; + assert(expression->is<Try>()); + static_cast<Try*>(expression)->delegateTarget = delegateTarget; +} +int BinaryenTryIsDelegate(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<Try>()); + return static_cast<Try*>(expression)->isDelegate(); +} // Throw const char* BinaryenThrowGetEvent(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; diff --git a/src/binaryen-c.h b/src/binaryen-c.h index eb0cfc6e1..967bb547f 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -802,13 +802,16 @@ BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module, BINARYEN_API BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module, BinaryenExpressionRef left, BinaryenExpressionRef right); +// Try: name can be NULL. delegateTarget should be NULL in try-catch. BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, + const char* name, BinaryenExpressionRef body, const char** catchEvents, BinaryenIndex numCatchEvents, BinaryenExpressionRef* catchBodies, - BinaryenIndex numCatchBodies); + BinaryenIndex numCatchBodies, + const char* delegateTarget); BINARYEN_API BinaryenExpressionRef BinaryenThrow(BinaryenModuleRef module, const char* event, @@ -1719,6 +1722,11 @@ BINARYEN_API void BinaryenRefEqSetRight(BinaryenExpressionRef expr, // Try +// Gets the name (label) of a `try` expression. +BINARYEN_API const char* BinaryenTryGetName(BinaryenExpressionRef expr); +// Sets the name (label) of a `try` expression. +BINARYEN_API void BinaryenTrySetName(BinaryenExpressionRef expr, + const char* name); // Gets the body expression of a `try` expression. BINARYEN_API BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr); @@ -1774,8 +1782,16 @@ BINARYEN_API void BinaryenTryInsertCatchBodyAt(BinaryenExpressionRef expr, // expression. BINARYEN_API BinaryenExpressionRef BinaryenTryRemoveCatchBodyAt(BinaryenExpressionRef expr, BinaryenIndex index); -// Gets whether an `try` expression has a catch_all clause. +// Gets whether a `try` expression has a catch_all clause. BINARYEN_API int BinaryenTryHasCatchAll(BinaryenExpressionRef expr); +// Gets the target label of a `delegate`. +BINARYEN_API const char* +BinaryenTryGetDelegateTarget(BinaryenExpressionRef expr); +// Sets the target label of a `delegate`. +BINARYEN_API void BinaryenTrySetDelegateTarget(BinaryenExpressionRef expr, + const char* delegateTarget); +// Gets whether a `try` expression is a try-delegate. +BINARYEN_API int BinaryenTryIsDelegate(BinaryenExpressionRef expr); // Throw diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 2ac2605fa..63be4d446 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -2147,9 +2147,9 @@ function wrapModule(module, self = {}) { } }; - self['try'] = function(body, catchEvents, catchBodies) { + self['try'] = function(name, body, catchEvents, catchBodies, delegateTarget) { return preserveStack(() => - Module['_BinaryenTry'](module, body, i32sToStack(catchEvents.map(strToStack)), catchEvents.length, i32sToStack(catchBodies), catchBodies.length)); + Module['_BinaryenTry'](module, name ? strToStack(name) : 0, body, i32sToStack(catchEvents.map(strToStack)), catchEvents.length, i32sToStack(catchBodies), catchBodies.length, delegateTarget ? strToStack(delegateTarget) : 0)); }; self['throw'] = function(event_, operands) { return preserveStack(() => Module['_BinaryenThrow'](module, strToStack(event_), i32sToStack(operands), operands.length)); @@ -2897,10 +2897,13 @@ Module['getExpressionInfo'] = function(expr) { return { 'id': id, 'type': type, + 'name': UTF8ToString(Module['_BinaryenTryGetName'](expr)), 'body': Module['_BinaryenTryGetBody'](expr), 'catchEvents': getAllNested(expr, Module['_BinaryenTryGetNumCatchEvents'], Module['_BinaryenTryGetCatchEventAt']), 'catchBodies': getAllNested(expr, Module['_BinaryenTryGetNumCatchBodies'], Module['_BinaryenTryGetCatchBodyAt']), - 'hasCatchAll': Module['_BinaryenTryHasCatchAll'](expr) + 'hasCatchAll': Module['_BinaryenTryHasCatchAll'](expr), + 'delegateTarget': UTF8ToString(Module['_BinaryenTryGetDelegateTarget'](expr)), + 'isDelegate': Module['_BinaryenTryIsDelegate'](expr) }; case Module['ThrowId']: return { @@ -4172,6 +4175,13 @@ Module['RefEq'] = makeExpressionWrapper({ }); Module['Try'] = makeExpressionWrapper({ + 'getName'(expr) { + const name = Module['_BinaryenTryGetName'](expr); + return name ? UTF8ToString(name) : null; + }, + 'setName'(expr, name) { + preserveStack(() => { Module['_BinaryenTrySetName'](expr, strToStack(name)) }); + }, 'getBody'(expr) { return Module['_BinaryenTryGetBody'](expr); }, @@ -4231,6 +4241,16 @@ Module['Try'] = makeExpressionWrapper({ 'hasCatchAll'(expr) { return Boolean(Module['_BinaryenTryHasCatchAll'](expr)); }, + 'getDelegateTarget'(expr) { + const name = Module['_BinaryenTryGetDelegateTarget'](expr); + return name ? UTF8ToString(name) : null; + }, + 'setDelegateTarget'(expr, name) { + preserveStack(() => { Module['_BinaryenTrySetDelegateTarget'](expr, strToStack(name)) }); + }, + 'isDelegate'(expr) { + return Boolean(Module['_BinaryenTryIsDelegate'](expr)); + } }); Module['Throw'] = makeExpressionWrapper({ diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 3a4ae97c1..fb67597b9 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -637,26 +637,66 @@ public: ret->finalize(); return ret; } - Try* makeTry(Expression* body, + +private: + Try* makeTry(Name name, + Expression* body, const std::vector<Name>& catchEvents, - const std::vector<Expression*>& catchBodies) { + const std::vector<Expression*>& catchBodies, + Name delegateTarget, + Type type, + bool hasType) { // differentiate whether a type was passed in auto* ret = wasm.allocator.alloc<Try>(); + ret->name = name; ret->body = body; ret->catchEvents.set(catchEvents); ret->catchBodies.set(catchBodies); - ret->finalize(); + if (hasType) { + ret->finalize(type); + } else { + ret->finalize(); + } return ret; } + +public: + Try* makeTry(Expression* body, + const std::vector<Name>& catchEvents, + const std::vector<Expression*>& catchBodies) { + return makeTry( + Name(), body, catchEvents, catchBodies, Name(), Type::none, false); + } Try* makeTry(Expression* body, const std::vector<Name>& catchEvents, const std::vector<Expression*>& catchBodies, Type type) { - auto* ret = wasm.allocator.alloc<Try>(); - ret->body = body; - ret->catchEvents.set(catchEvents); - ret->catchBodies.set(catchBodies); - ret->finalize(type); - return ret; + return makeTry(Name(), body, catchEvents, catchBodies, Name(), type, true); + } + Try* makeTry(Name name, + Expression* body, + const std::vector<Name>& catchEvents, + const std::vector<Expression*>& catchBodies) { + return makeTry( + name, body, catchEvents, catchBodies, Name(), Type::none, false); + } + Try* makeTry(Name name, + Expression* body, + const std::vector<Name>& catchEvents, + const std::vector<Expression*>& catchBodies, + Type type) { + return makeTry(name, body, catchEvents, catchBodies, Name(), type, true); + } + Try* makeTry(Expression* body, Name delegateTarget) { + return makeTry(Name(), body, {}, {}, delegateTarget, Type::none, false); + } + Try* makeTry(Expression* body, Name delegateTarget, Type type) { + return makeTry(Name(), body, {}, {}, delegateTarget, type, true); + } + Try* makeTry(Name name, Expression* body, Name delegateTarget) { + return makeTry(name, body, {}, {}, delegateTarget, Type::none, false); + } + Try* makeTry(Name name, Expression* body, Name delegateTarget, Type type) { + return makeTry(name, body, {}, {}, delegateTarget, type, true); } Throw* makeThrow(Event* event, const std::vector<Expression*>& args) { return makeThrow(event->name, args); diff --git a/test/binaryen.js/exception-handling.js b/test/binaryen.js/exception-handling.js index e6cadcf88..40dc9d489 100644 --- a/test/binaryen.js/exception-handling.js +++ b/test/binaryen.js/exception-handling.js @@ -3,7 +3,8 @@ function cleanInfo(info) { for (var x in info) { // Filter out address pointers and only print meaningful info if (x == 'id' || x == 'type' || x == 'name' || x == 'event' || - x == 'depth' || x == 'hasCatchAll') { + x == 'depth' || x == 'hasCatchAll' || x == 'delegateTarget' || + x == 'isDelegate') { ret[x] = info[x]; } } @@ -31,7 +32,8 @@ var event_ = module.addEvent("e", 0, binaryen.i32, binaryen.none); // ) var throw_ = module.throw("e", [module.i32.const(0)]); var rethrow = module.rethrow(0); -var try_ = module.try( +var try_catch = module.try( + '', throw_, ["e"], [ @@ -42,14 +44,42 @@ var try_ = module.try( ], binaryen.none ) - ] + ], + '' ); -var func = module.addFunction("test", binaryen.none, binaryen.none, [], try_); +// (try $try_outer +// (do +// (try +// (do +// (throw $a-event (i32.const 0)) +// ) +// (delegate $try_outer) +// ) +// ) +// (catch_all) +// ) +var try_delegate = module.try( + 'try_outer', + module.try( + '', + throw_, + [], + [], + 'try_outer' + ), + [], + [module.nop()], + '' +); + +var body = module.block('', [try_catch, try_delegate]) +var func = module.addFunction("test", binaryen.none, binaryen.none, [], body); console.log(module.emitText()); assert(module.validate()); console.log("getExpressionInfo(throw) = " + stringify(throw_)); console.log("getExpressionInfo(rethrow) = " + stringify(rethrow)); -console.log("getExpressionInfo(try) = " + stringify(try_)); +console.log("getExpressionInfo(try_catch) = " + stringify(try_catch)); +console.log("getExpressionInfo(try_delegate) = " + stringify(try_delegate)); diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index 69b619564..350d543e5 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -16,9 +16,25 @@ (rethrow 0) ) ) + (try $try_outer + (do + (try + (do + (throw $e + (i32.const 0) + ) + ) + (delegate $try_outer) + ) + ) + (catch_all + (nop) + ) + ) ) ) getExpressionInfo(throw) = {"id":48,"type":1,"event":"e"} getExpressionInfo(rethrow) = {"id":49,"type":1,"depth":0} -getExpressionInfo(try) = {"id":47,"type":1,"hasCatchAll":0} +getExpressionInfo(try_catch) = {"id":47,"type":1,"name":"","hasCatchAll":0,"delegateTarget":"","isDelegate":0} +getExpressionInfo(try_delegate) = {"id":47,"type":0,"name":"try_outer","hasCatchAll":1,"delegateTarget":"","isDelegate":0} diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index 4c97cdb90..688321675 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -1469,7 +1469,7 @@ console.log("# Try"); module.i32.const(2), module.i32.const(3) ]; - const theTry = binaryen.Try(module.try(body, ["event1"], catchBodies)); + const theTry = binaryen.Try(module.try('', body, ["event1"], catchBodies, '')); assert(theTry instanceof binaryen.Try); assert(theTry instanceof binaryen.Expression); assert(theTry.body === body); @@ -1523,6 +1523,14 @@ console.log("# Try"); assert(theTry.type === binaryen.i32); console.log(theTry.toText()); + + const tryDelegate = binaryen.Try(module.try('', body, [], [], "try_blah")); + assert(tryDelegate.isDelegate() == 1); + assert(tryDelegate.getDelegateTarget() == "try_blah"); + tryDelegate.setDelegateTarget("try_outer"); + assert(tryDelegate.getDelegateTarget() == "try_outer"); + console.log(tryDelegate.toText()); + module.dispose(); })(); diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt index 80a642af8..8467c55c0 100644 --- a/test/binaryen.js/expressions.js.txt +++ b/test/binaryen.js/expressions.js.txt @@ -283,6 +283,13 @@ ) ) +(try (result i32) + (do + (i32.const 4) + ) + (delegate $try_outer) +) + # Throw (throw $bar (i32.const 6) diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 327cf0534..2a28cc5b2 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -545,9 +545,11 @@ function test_core() { // Exception handling module.try( + '', module.throw("a-event", [module.i32.const(0)]), ["a-event"], - [module.drop(module.i32.pop())] + [module.drop(module.i32.pop())], + '' ), // Atomics diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index b45039c69..359203e8b 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -336,8 +336,11 @@ void test_core() { BinaryenExpressionRef catchBody = BinaryenDrop(module, BinaryenPop(module, BinaryenTypeInt32())); BinaryenExpressionRef catchAllBody = BinaryenNop(module); - BinaryenExpressionRef catchBodies[] = {catchBody, catchAllBody}; const char* catchEvents[] = {"a-event"}; + BinaryenExpressionRef catchBodies[] = {catchBody, catchAllBody}; + const char* emptyCatchEvents[] = {}; + BinaryenExpressionRef emptyCatchBodies[] = {}; + BinaryenExpressionRef nopCatchBody[] = {BinaryenNop(module)}; BinaryenType i32 = BinaryenTypeInt32(); BinaryenType i64 = BinaryenTypeInt64(); @@ -727,7 +730,33 @@ void test_core() { BinaryenRefNull(module, BinaryenTypeEqref()), BinaryenRefNull(module, BinaryenTypeEqref())), // Exception handling - BinaryenTry(module, tryBody, catchEvents, 1, catchBodies, 2), + BinaryenTry(module, NULL, tryBody, catchEvents, 1, catchBodies, 2, NULL), + // (try $try_outer + // (do + // (try + // (do + // (throw $a-event (i32.const 0)) + // ) + // (delegate $try_outer) + // ) + // ) + // (catch_all) + // ) + BinaryenTry(module, + "try_outer", + BinaryenTry(module, + NULL, + tryBody, + emptyCatchEvents, + 0, + emptyCatchBodies, + 0, + "try_outer"), + emptyCatchEvents, + 0, + nopCatchBody, + 1, + NULL), // Atomics BinaryenAtomicStore( module, diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index f03e4ec6c..c3226690e 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -1775,6 +1775,21 @@ BinaryenFeatureAll: 8191 (nop) ) ) + (try $try_outer + (do + (try + (do + (throw $a-event + (i32.const 0) + ) + ) + (delegate $try_outer) + ) + ) + (catch_all + (nop) + ) + ) (i32.atomic.store (i32.const 0) (i32.atomic.load |