Skip to content

[EH] Update C and binaryen.js API for delegate #3565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>());
Expand Down Expand Up @@ -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;
Expand Down
20 changes: 18 additions & 2 deletions src/binaryen-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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

Expand Down
26 changes: 23 additions & 3 deletions src/js/binaryen.js-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
},
Expand Down Expand Up @@ -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({
Expand Down
58 changes: 49 additions & 9 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,26 +637,66 @@ class Builder {
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);
Expand Down
40 changes: 35 additions & 5 deletions test/binaryen.js/exception-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
}
Expand Down Expand Up @@ -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"],
[
Expand All @@ -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));
18 changes: 17 additions & 1 deletion test/binaryen.js/exception-handling.js.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
10 changes: 9 additions & 1 deletion test/binaryen.js/expressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
})();

Expand Down
7 changes: 7 additions & 0 deletions test/binaryen.js/expressions.js.txt
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@
)
)

(try (result i32)
(do
(i32.const 4)
)
(delegate $try_outer)
)

# Throw
(throw $bar
(i32.const 6)
Expand Down
Loading