summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/binaryen-c.cpp52
-rw-r--r--src/binaryen-c.h20
-rw-r--r--src/js/binaryen.js-post.js26
-rw-r--r--src/wasm-builder.h58
-rw-r--r--test/binaryen.js/exception-handling.js40
-rw-r--r--test/binaryen.js/exception-handling.js.txt18
-rw-r--r--test/binaryen.js/expressions.js10
-rw-r--r--test/binaryen.js/expressions.js.txt7
-rw-r--r--test/binaryen.js/kitchen-sink.js4
-rw-r--r--test/example/c-api-kitchen-sink.c33
-rw-r--r--test/example/c-api-kitchen-sink.txt15
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