diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 55e6f330724..2f2f0d3ddac 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -226,6 +226,12 @@ BinaryenType BinaryenTypeNullExternref(void) { BinaryenType BinaryenTypeNullFuncref(void) { return Type(HeapType::nofunc, Nullable).getID(); } +BinaryenType BinaryenTypeExnref(void) { + return Type(HeapType::exn, Nullable).getID(); +} +BinaryenType BinaryenTypeNullExnref(void) { + return Type(HeapType::noexn, Nullable).getID(); +} BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; } BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); } @@ -302,6 +308,12 @@ BinaryenHeapType BinaryenHeapTypeNoext() { BinaryenHeapType BinaryenHeapTypeNofunc() { return static_cast(HeapType::BasicHeapType::nofunc); } +BinaryenHeapType BinaryenHeapTypeExn() { + return static_cast(HeapType::BasicHeapType::exn); +} +BinaryenHeapType BinaryenHeapTypeNoexn() { + return static_cast(HeapType::BasicHeapType::noexn); +} bool BinaryenHeapTypeIsBasic(BinaryenHeapType heapType) { return HeapType(heapType).isBasic(); @@ -1780,6 +1792,28 @@ BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, return static_cast(ret); } +BinaryenExpressionRef BinaryenTryTable(BinaryenModuleRef module, + BinaryenExpressionRef body, + const char** catchTags, + const char** catchDests, + const bool* catchRefs, + BinaryenIndex numCatches) { + std::vector tags; + std::vector dests; + std::vector refs; + tags.reserve(numCatches); + dests.reserve(numCatches); + refs.reserve(numCatches); + for (BinaryenIndex i = 0; i < numCatches; i++) { + tags.push_back(catchTags[i] ? Name(catchTags[i]) : Name()); + dests.push_back(catchDests[i]); + refs.push_back(catchRefs[i]); + } + return static_cast( + Builder(*(Module*)module) + .makeTryTable((Expression*)body, tags, dests, refs)); +} + BinaryenExpressionRef BinaryenThrow(BinaryenModuleRef module, const char* tag, BinaryenExpressionRef* operands, @@ -1798,6 +1832,12 @@ BinaryenExpressionRef BinaryenRethrow(BinaryenModuleRef module, Builder(*(Module*)module).makeRethrow(target)); } +BinaryenExpressionRef BinaryenThrowRef(BinaryenModuleRef module, + BinaryenExpressionRef exnref) { + return static_cast( + Builder(*(Module*)module).makeThrowRef((Expression*)exnref)); +} + BinaryenExpressionRef BinaryenRefI31(BinaryenModuleRef module, BinaryenExpressionRef value) { return static_cast( @@ -4086,6 +4126,112 @@ bool BinaryenTryIsDelegate(BinaryenExpressionRef expr) { assert(expression->is()); return static_cast(expression)->isDelegate(); } +// TryTable +BinaryenExpressionRef BinaryenTryTableGetBody(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + return static_cast(expression)->body; +} +void BinaryenTryTableSetBody(BinaryenExpressionRef expr, + BinaryenExpressionRef bodyExpr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(bodyExpr); + static_cast(expression)->body = (Expression*)bodyExpr; +} +BinaryenIndex BinaryenTryTableGetNumCatches(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + return static_cast(expression)->catchTags.size(); +} +const char* BinaryenTryTableGetCatchTagAt(BinaryenExpressionRef expr, + BinaryenIndex index) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchTags.size()); + auto name = static_cast(expression)->catchTags[index]; + return name.is() ? name.str.data() : nullptr; +} +void BinaryenTryTableSetCatchTagAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchTag) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchTags.size()); + static_cast(expression)->catchTags[index] = + catchTag ? Name(catchTag) : Name(); +} +const char* BinaryenTryTableGetCatchDestAt(BinaryenExpressionRef expr, + BinaryenIndex index) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchDests.size()); + return static_cast(expression)->catchDests[index].str.data(); +} +void BinaryenTryTableSetCatchDestAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchDest) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchDests.size()); + static_cast(expression)->catchDests[index] = catchDest; +} +bool BinaryenTryTableIsCatchRefAt(BinaryenExpressionRef expr, + BinaryenIndex index) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchRefs.size()); + return static_cast(expression)->catchRefs[index]; +} +void BinaryenTryTableSetCatchRefAt(BinaryenExpressionRef expr, + BinaryenIndex index, + bool catchRef) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(index < static_cast(expression)->catchRefs.size()); + static_cast(expression)->catchRefs[index] = catchRef; +} +BinaryenIndex BinaryenTryTableAppendCatch(BinaryenExpressionRef expr, + const char* catchTag, + const char* catchDest, + bool catchRef) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(catchDest); + auto* tryTable = static_cast(expression); + auto index = tryTable->catchTags.size(); + tryTable->catchTags.push_back(catchTag ? Name(catchTag) : Name()); + tryTable->catchDests.push_back(Name(catchDest)); + tryTable->catchRefs.push_back(catchRef); + return index; +} +void BinaryenTryTableInsertCatchAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchTag, + const char* catchDest, + bool catchRef) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(catchDest); + auto* tryTable = static_cast(expression); + tryTable->catchTags.insertAt(index, catchTag ? Name(catchTag) : Name()); + tryTable->catchDests.insertAt(index, Name(catchDest)); + tryTable->catchRefs.insertAt(index, catchRef); +} +const char* BinaryenTryTableRemoveCatchAt(BinaryenExpressionRef expr, + BinaryenIndex index) { + auto* expression = (Expression*)expr; + assert(expression->is()); + auto* tryTable = static_cast(expression); + tryTable->catchTags.removeAt(index); + tryTable->catchRefs.removeAt(index); + return tryTable->catchDests.removeAt(index).str.data(); +} +bool BinaryenTryTableHasCatchAll(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + return static_cast(expression)->hasCatchAll(); +} // Throw const char* BinaryenThrowGetTag(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; @@ -4154,6 +4300,19 @@ void BinaryenRethrowSetTarget(BinaryenExpressionRef expr, const char* target) { assert(expression->is()); static_cast(expression)->target = target; } +// ThrowRef +BinaryenExpressionRef BinaryenThrowRefGetExnref(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + return static_cast(expression)->exnref; +} +void BinaryenThrowRefSetExnref(BinaryenExpressionRef expr, + BinaryenExpressionRef exnrefExpr) { + auto* expression = (Expression*)expr; + assert(expression->is()); + assert(exnrefExpr); + static_cast(expression)->exnref = (Expression*)exnrefExpr; +} // TupleMake BinaryenIndex BinaryenTupleMakeGetNumOperands(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; diff --git a/src/binaryen-c.h b/src/binaryen-c.h index a6bb2e0a6a4..d550e42d04e 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -112,6 +112,8 @@ BINARYEN_API BinaryenType BinaryenTypeStringref(void); BINARYEN_API BinaryenType BinaryenTypeNullref(void); BINARYEN_API BinaryenType BinaryenTypeNullExternref(void); BINARYEN_API BinaryenType BinaryenTypeNullFuncref(void); +BINARYEN_API BinaryenType BinaryenTypeExnref(void); +BINARYEN_API BinaryenType BinaryenTypeNullExnref(void); BINARYEN_API BinaryenType BinaryenTypeUnreachable(void); // Not a real type. Used as the last parameter to BinaryenBlock to let // the API figure out the type instead of providing one. @@ -151,6 +153,8 @@ BINARYEN_API BinaryenHeapType BinaryenHeapTypeString(void); BINARYEN_API BinaryenHeapType BinaryenHeapTypeNone(void); BINARYEN_API BinaryenHeapType BinaryenHeapTypeNoext(void); BINARYEN_API BinaryenHeapType BinaryenHeapTypeNofunc(void); +BINARYEN_API BinaryenHeapType BinaryenHeapTypeExn(void); +BINARYEN_API BinaryenHeapType BinaryenHeapTypeNoexn(void); BINARYEN_API bool BinaryenHeapTypeIsBasic(BinaryenHeapType heapType); BINARYEN_API bool BinaryenHeapTypeIsSignature(BinaryenHeapType heapType); @@ -1037,6 +1041,14 @@ BinaryenTry(BinaryenModuleRef module, BinaryenExpressionRef* catchBodies, BinaryenIndex numCatchBodies, const char* delegateTarget); +// TryTable: catch tag names may be NULL to denote catch_all or catch_all_ref. +// catchRefs[i] is true if the i-th catch is catch_ref or catch_all_ref. +BINARYEN_API BinaryenExpressionRef BinaryenTryTable(BinaryenModuleRef module, + BinaryenExpressionRef body, + const char** catchTags, + const char** catchDests, + const bool* catchRefs, + BinaryenIndex numCatches); BINARYEN_API BinaryenExpressionRef BinaryenThrow(BinaryenModuleRef module, const char* tag, @@ -1045,6 +1057,8 @@ BinaryenThrow(BinaryenModuleRef module, BINARYEN_API BinaryenExpressionRef BinaryenRethrow(BinaryenModuleRef module, const char* target); BINARYEN_API BinaryenExpressionRef +BinaryenThrowRef(BinaryenModuleRef module, BinaryenExpressionRef exnref); +BINARYEN_API BinaryenExpressionRef BinaryenTupleMake(BinaryenModuleRef module, BinaryenExpressionRef* operands, BinaryenIndex numOperands); @@ -2362,6 +2376,67 @@ BINARYEN_API void BinaryenTrySetDelegateTarget(BinaryenExpressionRef expr, // Gets whether a `try` expression is a try-delegate. BINARYEN_API bool BinaryenTryIsDelegate(BinaryenExpressionRef expr); +// TryTable + +// Gets the body expression of a `try_table` expression. +BINARYEN_API BinaryenExpressionRef +BinaryenTryTableGetBody(BinaryenExpressionRef expr); +// Sets the body expression of a `try_table` expression. +BINARYEN_API void BinaryenTryTableSetBody(BinaryenExpressionRef expr, + BinaryenExpressionRef bodyExpr); +// Gets the number of catch clauses of a `try_table` expression. +BINARYEN_API BinaryenIndex +BinaryenTryTableGetNumCatches(BinaryenExpressionRef expr); +// Gets the catch tag at the specified index of a `try_table` expression. Empty +// (NULL) for catch_all and catch_all_ref clauses. +BINARYEN_API const char* +BinaryenTryTableGetCatchTagAt(BinaryenExpressionRef expr, BinaryenIndex index); +// Sets the catch tag at the specified index of a `try_table` expression. Pass +// NULL for catch_all/catch_all_ref clauses. +BINARYEN_API void BinaryenTryTableSetCatchTagAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchTag); +// Gets the catch destination label at the specified index of a `try_table` +// expression. +BINARYEN_API const char* +BinaryenTryTableGetCatchDestAt(BinaryenExpressionRef expr, BinaryenIndex index); +// Sets the catch destination label at the specified index of a `try_table` +// expression. +BINARYEN_API void BinaryenTryTableSetCatchDestAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchDest); +// Gets whether the catch clause at the specified index of a `try_table` +// expression is a `catch_ref` or `catch_all_ref` clause (passes the exnref). +BINARYEN_API bool BinaryenTryTableIsCatchRefAt(BinaryenExpressionRef expr, + BinaryenIndex index); +// Sets whether the catch clause at the specified index of a `try_table` +// expression is a `catch_ref`/`catch_all_ref` clause. +BINARYEN_API void BinaryenTryTableSetCatchRefAt(BinaryenExpressionRef expr, + BinaryenIndex index, + bool catchRef); +// Appends a catch clause to a `try_table` expression, returning its insertion +// index. Pass NULL for `catchTag` for catch_all/catch_all_ref. +BINARYEN_API BinaryenIndex +BinaryenTryTableAppendCatch(BinaryenExpressionRef expr, + const char* catchTag, + const char* catchDest, + bool catchRef); +// Inserts a catch clause at the specified index of a `try_table` expression, +// moving existing clauses including the one previously at that index one +// index up. +BINARYEN_API void BinaryenTryTableInsertCatchAt(BinaryenExpressionRef expr, + BinaryenIndex index, + const char* catchTag, + const char* catchDest, + bool catchRef); +// Removes the catch clause at the specified index of a `try_table` expression, +// moving all subsequent clauses one index down. Returns the removed clause's +// destination label. +BINARYEN_API const char* +BinaryenTryTableRemoveCatchAt(BinaryenExpressionRef expr, BinaryenIndex index); +// Gets whether a `try_table` expression has a catch_all/catch_all_ref clause. +BINARYEN_API bool BinaryenTryTableHasCatchAll(BinaryenExpressionRef expr); + // Throw // Gets the name of the tag being thrown by a `throw` expression. @@ -2404,6 +2479,15 @@ BINARYEN_API const char* BinaryenRethrowGetTarget(BinaryenExpressionRef expr); BINARYEN_API void BinaryenRethrowSetTarget(BinaryenExpressionRef expr, const char* target); +// ThrowRef + +// Gets the exnref operand of a `throw_ref` expression. +BINARYEN_API BinaryenExpressionRef +BinaryenThrowRefGetExnref(BinaryenExpressionRef expr); +// Sets the exnref operand of a `throw_ref` expression. +BINARYEN_API void BinaryenThrowRefSetExnref(BinaryenExpressionRef expr, + BinaryenExpressionRef exnrefExpr); + // TupleMake // Gets the number of operands of a `tuple.make` expression. diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 1ad2531371d..b04996952eb 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -46,6 +46,8 @@ function initializeConstants() { ['nullref', 'Nullref'], ['nullexternref', 'NullExternref'], ['nullfuncref', 'NullFuncref'], + ['exnref', 'Exnref'], + ['nullexnref', 'NullExnref'], ['unreachable', 'Unreachable'], ['auto', 'Auto'] ].forEach(entry => { @@ -68,6 +70,8 @@ function initializeConstants() { */ ['noextern', 'Noext'], ['nofunc', 'Nofunc'], + ['exn', 'Exn'], + ['noexn', 'Noexn'], ].forEach(entry => { Module[entry[0]] = Module['_BinaryenHeapType' + entry[1]](); }); @@ -130,8 +134,10 @@ function initializeConstants() { 'TableSize', 'TableGrow', 'Try', + 'TryTable', 'Throw', 'Rethrow', + 'ThrowRef', 'TupleMake', 'TupleExtract', 'Pop', @@ -2515,12 +2521,24 @@ function wrapModule(module, self = {}) { return preserveStack(() => Module['_BinaryenTry'](module, name ? strToStack(name) : 0, body, i32sToStack(catchTags.map(strToStack)), catchTags.length, i32sToStack(catchBodies), catchBodies.length, delegateTarget ? strToStack(delegateTarget) : 0)); }; + self['try_table'] = function(body, catches) { + return preserveStack(() => { + const numCatches = catches.length; + const tagsPtr = i32sToStack(catches.map(c => c['tag'] ? strToStack(c['tag']) : 0)); + const destsPtr = i32sToStack(catches.map(c => strToStack(c['dest']))); + const refsPtr = i8sToStack(catches.map(c => c['ref'] ? 1 : 0)); + return Module['_BinaryenTryTable'](module, body, tagsPtr, destsPtr, refsPtr, numCatches); + }); + }; self['throw'] = function(tag, operands) { return preserveStack(() => Module['_BinaryenThrow'](module, strToStack(tag), i32sToStack(operands), operands.length)); }; self['rethrow'] = function(target) { return preserveStack(() => Module['_BinaryenRethrow'](module, strToStack(target))); }; + self['throw_ref'] = function(exnref) { + return Module['_BinaryenThrowRef'](module, exnref); + }; self['tuple'] = { 'make'(elements) { @@ -5343,6 +5361,76 @@ Module['Try'] = makeExpressionWrapper(Module['_BinaryenTryId'](), { } }); +function getTryTableCatchAt(expr, index) { + const tagPtr = Module['_BinaryenTryTableGetCatchTagAt'](expr, index); + return { + 'tag': tagPtr ? UTF8ToString(tagPtr) : null, + 'dest': UTF8ToString(Module['_BinaryenTryTableGetCatchDestAt'](expr, index)), + 'ref': Boolean(Module['_BinaryenTryTableIsCatchRefAt'](expr, index)) + }; +} + +Module['TryTable'] = makeExpressionWrapper(Module['_BinaryenTryTableId'](), { + 'getBody'(expr) { + return Module['_BinaryenTryTableGetBody'](expr); + }, + 'setBody'(expr, bodyExpr) { + Module['_BinaryenTryTableSetBody'](expr, bodyExpr); + }, + 'getNumCatches'(expr) { + return Module['_BinaryenTryTableGetNumCatches'](expr); + }, + 'getCatches'(expr) { + const num = Module['_BinaryenTryTableGetNumCatches'](expr); + const ret = new Array(num); + for (let i = 0; i < num; ++i) ret[i] = getTryTableCatchAt(expr, i); + return ret; + }, + 'setCatches'(expr, catches) { + const num = catches.length; + let prevNum = Module['_BinaryenTryTableGetNumCatches'](expr); + preserveStack(() => { + for (let i = 0; i < num; ++i) { + const c = catches[i]; + const tag = c['tag'] ? strToStack(c['tag']) : 0; + const dest = strToStack(c['dest']); + const ref = c['ref'] ? 1 : 0; + if (i < prevNum) { + Module['_BinaryenTryTableSetCatchTagAt'](expr, i, tag); + Module['_BinaryenTryTableSetCatchDestAt'](expr, i, dest); + Module['_BinaryenTryTableSetCatchRefAt'](expr, i, ref); + } else { + Module['_BinaryenTryTableAppendCatch'](expr, tag, dest, ref); + } + } + }); + while (prevNum > num) Module['_BinaryenTryTableRemoveCatchAt'](expr, --prevNum); + }, + 'getCatchAt': getTryTableCatchAt, + 'setCatchAt'(expr, index, c) { + preserveStack(() => { + Module['_BinaryenTryTableSetCatchTagAt'](expr, index, c['tag'] ? strToStack(c['tag']) : 0); + Module['_BinaryenTryTableSetCatchDestAt'](expr, index, strToStack(c['dest'])); + Module['_BinaryenTryTableSetCatchRefAt'](expr, index, c['ref'] ? 1 : 0); + }); + }, + 'appendCatch'(expr, c) { + return preserveStack(() => + Module['_BinaryenTryTableAppendCatch'](expr, c['tag'] ? strToStack(c['tag']) : 0, strToStack(c['dest']), c['ref'] ? 1 : 0)); + }, + 'insertCatchAt'(expr, index, c) { + preserveStack(() => { + Module['_BinaryenTryTableInsertCatchAt'](expr, index, c['tag'] ? strToStack(c['tag']) : 0, strToStack(c['dest']), c['ref'] ? 1 : 0); + }); + }, + 'removeCatchAt'(expr, index) { + return UTF8ToString(Module['_BinaryenTryTableRemoveCatchAt'](expr, index)); + }, + 'hasCatchAll'(expr) { + return Boolean(Module['_BinaryenTryTableHasCatchAll'](expr)); + } +}); + Module['Throw'] = makeExpressionWrapper(Module['_BinaryenThrowId'](), { 'getTag'(expr) { return UTF8ToString(Module['_BinaryenThrowGetTag'](expr)); @@ -5386,6 +5474,15 @@ Module['Rethrow'] = makeExpressionWrapper(Module['_BinaryenRethrowId'](), { } }); +Module['ThrowRef'] = makeExpressionWrapper(Module['_BinaryenThrowRefId'](), { + 'getExnref'(expr) { + return Module['_BinaryenThrowRefGetExnref'](expr); + }, + 'setExnref'(expr, exnrefExpr) { + Module['_BinaryenThrowRefSetExnref'](expr, exnrefExpr); + } +}); + Module['TupleMake'] = makeExpressionWrapper(Module['_BinaryenTupleMakeId'](), { 'getNumOperands'(expr) { return Module['_BinaryenTupleMakeGetNumOperands'](expr); diff --git a/test/binaryen.js/exception-handling.js b/test/binaryen.js/exception-handling.js index ec158552124..2a585137775 100644 --- a/test/binaryen.js/exception-handling.js +++ b/test/binaryen.js/exception-handling.js @@ -4,7 +4,8 @@ function cleanInfo(info) { // Filter out address pointers and only print meaningful info if (x == 'id' || x == 'type' || x == 'name' || x == 'tag' || x == 'target' || x == 'hasCatchAll' || x == 'delegateTarget' || - x == 'isDelegate') { + x == 'isDelegate' || x == 'numCatches' || x == 'catches' || + x == 'catchTags') { ret[x] = info[x]; } } @@ -73,7 +74,21 @@ var try_delegate = module.try( '' ); -var body = module.block('', [try_catch, try_delegate]) +// (block $catch_all_dest +// (try_table (catch_all $catch_all_dest) +// (throw $e (i32.const 0)) +// ) +// ) +var try_table = module.try_table( + module.throw("e", [module.i32.const(0)]), + [{ tag: null, dest: "catch_all_dest", ref: false }] +); +var try_table_block = module.block("catch_all_dest", [try_table], binaryen.none); + +// (throw_ref (ref.null noexn)) +var throw_ref = module.throw_ref(module.ref.null(binaryen.noexn)); + +var body = module.block('', [try_catch, try_delegate, try_table_block, throw_ref]) var func = module.addFunction("test", binaryen.none, binaryen.none, [], body); console.log(module.emitText()); @@ -83,3 +98,5 @@ console.log("getExpressionInfo(throw) = " + stringify(throw_)); console.log("getExpressionInfo(rethrow) = " + stringify(rethrow)); console.log("getExpressionInfo(try_catch) = " + stringify(try_catch)); console.log("getExpressionInfo(try_delegate) = " + stringify(try_delegate)); +console.log("getExpressionInfo(try_table) = " + stringify(try_table)); +console.log("getExpressionInfo(throw_ref) = " + stringify(throw_ref)); diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index a26860f3eff..c4979fcd33a 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -31,10 +31,22 @@ (nop) ) ) + (block $catch_all_dest + (try_table (catch_all $catch_all_dest) + (throw $e + (i32.const 0) + ) + ) + ) + (throw_ref + (ref.null noexn) + ) ) ) getExpressionInfo(throw) = {"id":56,"type":1,"tag":"e"} getExpressionInfo(rethrow) = {"id":57,"type":1,"target":"l0"} -getExpressionInfo(try_catch) = {"id":54,"type":1,"name":"l0","hasCatchAll":false,"delegateTarget":null,"isDelegate":false} -getExpressionInfo(try_delegate) = {"id":54,"type":0,"name":"try_outer","hasCatchAll":true,"delegateTarget":null,"isDelegate":false} +getExpressionInfo(try_catch) = {"id":54,"type":1,"name":"l0","catchTags":["e"],"hasCatchAll":false,"delegateTarget":null,"isDelegate":false} +getExpressionInfo(try_delegate) = {"id":54,"type":0,"name":"try_outer","catchTags":[],"hasCatchAll":true,"delegateTarget":null,"isDelegate":false} +getExpressionInfo(try_table) = {"id":55,"type":1,"numCatches":1,"catches":[{"tag":null,"dest":"catch_all_dest","ref":false}],"hasCatchAll":true} +getExpressionInfo(throw_ref) = {"id":58,"type":1} diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index de3550d6f3c..90290f284f3 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -3285,6 +3285,73 @@ console.log("# Try"); module.dispose(); })(); +console.log("# TryTable"); +(function testTryTable() { + const module = new binaryen.Module(); + module.addTag("tag1", 0, binaryen.none, binaryen.none); + module.addTag("tag2", 0, binaryen.none, binaryen.none); + + var body = module.nop(); + var catches = [ + { tag: "tag1", dest: "dest1", ref: false }, + { tag: null, dest: "dest_all", ref: true } + ]; + const theTryTable = binaryen.TryTable(module.try_table(body, catches)); + assert(theTryTable instanceof binaryen.TryTable); + assert(theTryTable instanceof binaryen.Expression); + assert(theTryTable.body === body); + assert(theTryTable.getNumCatches() == 2); + assertDeepEqual(theTryTable.catches, catches); + assertDeepEqual(theTryTable.getCatches(), catches); + assertDeepEqual(theTryTable.getCatchAt(0), catches[0]); + assert(theTryTable.hasCatchAll() == true); + console.log(theTryTable.toText()); + + var info = binaryen.getExpressionInfo(theTryTable); + assert(info.id === theTryTable.id); + assert(info.type === theTryTable.type); + assert(info.body === theTryTable.body); + assertDeepEqual(info.catches, theTryTable.catches); + assert(info.hasCatchAll === theTryTable.hasCatchAll()); + + theTryTable.body = body = module.unreachable(); + assert(theTryTable.body === body); + + theTryTable.setCatchAt(0, { tag: "tag2", dest: "new_dest1", ref: true }); + assertDeepEqual(theTryTable.getCatchAt(0), { tag: "tag2", dest: "new_dest1", ref: true }); + console.log(theTryTable.toText()); + + theTryTable.insertCatchAt(0, { tag: "tag1", dest: "first_dest", ref: false }); + assert(theTryTable.getNumCatches() == 3); + assertDeepEqual(theTryTable.getCatchAt(0), { tag: "tag1", dest: "first_dest", ref: false }); + console.log(theTryTable.toText()); + + assert(theTryTable.removeCatchAt(0) == "first_dest"); + assert(theTryTable.getNumCatches() == 2); + assertDeepEqual(theTryTable.getCatchAt(0), { tag: "tag2", dest: "new_dest1", ref: true }); + + theTryTable.appendCatch({ tag: "tag1", dest: "appended_dest", ref: true }); + assert(theTryTable.getNumCatches() == 3); + assertDeepEqual(theTryTable.getCatchAt(2), { tag: "tag1", dest: "appended_dest", ref: true }); + console.log(theTryTable.toText()); + + var newCatches = [ + { tag: "tag1", dest: "only_dest", ref: false } // set + // remove + // remove + ]; + theTryTable.catches = newCatches; + assert(theTryTable.getNumCatches() == 1); + assertDeepEqual(theTryTable.catches, newCatches); + console.log(theTryTable.toText()); + + theTryTable.type = binaryen.f64; + theTryTable.finalize(); + console.log(theTryTable.toText()); + + module.dispose(); +})(); + console.log("# Throw"); (function testThrow() { const module = new binaryen.Module(); @@ -3378,6 +3445,35 @@ console.log("# Rethrow"); module.dispose(); })(); +console.log("# ThrowRef"); +(function testThrowRef() { + const module = new binaryen.Module(); + + var exnref = module.ref.null(binaryen.noexn); + const theThrowRef = binaryen.ThrowRef(module.throw_ref(exnref)); + assert(theThrowRef instanceof binaryen.ThrowRef); + assert(theThrowRef instanceof binaryen.Expression); + assert(theThrowRef.exnref === exnref); + assert(theThrowRef.type === binaryen.unreachable); + + var info = binaryen.getExpressionInfo(theThrowRef); + assert(info.id === theThrowRef.id); + assert(info.type === theThrowRef.type); + assert(info.exnref === theThrowRef.exnref); + + var newExnref = module.ref.null(binaryen.noexn); + theThrowRef.exnref = newExnref; + assert(theThrowRef.exnref === newExnref); + + theThrowRef.type = binaryen.f64; + theThrowRef.finalize(); + assert(theThrowRef.type === binaryen.unreachable); + + console.log(theThrowRef.toText()); + + module.dispose(); +})(); + console.log("# TupleMake"); (function testTupleMake() { const module = new binaryen.Module(); diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt index d8f45dff8a5..dc3bb8decd5 100644 --- a/test/binaryen.js/expressions.js.txt +++ b/test/binaryen.js/expressions.js.txt @@ -451,6 +451,31 @@ (delegate $try_outer) ) +# TryTable +(try_table (catch $tag1 $dest1) (catch_all_ref $dest_all) + (nop) +) + +(try_table (catch_ref $tag2 $new_dest1) (catch_all_ref $dest_all) + (unreachable) +) + +(try_table (catch $tag1 $first_dest) (catch_ref $tag2 $new_dest1) (catch_all_ref $dest_all) + (unreachable) +) + +(try_table (catch_ref $tag2 $new_dest1) (catch_all_ref $dest_all) (catch_ref $tag1 $appended_dest) + (unreachable) +) + +(try_table (catch $tag1 $only_dest) + (unreachable) +) + +(try_table (catch $tag1 $only_dest) + (unreachable) +) + # Throw (throw $bar (i32.const 6) @@ -460,6 +485,11 @@ # Rethrow (rethrow $l1) +# ThrowRef +(throw_ref + (ref.null noexn) +) + # TupleMake (tuple.make 2 (i32.const 6) diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 327abb34dab..b558da24a9e 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -158,8 +158,10 @@ function test_ids() { console.log("TableSizeId: " + binaryen.TableSizeId); console.log("TableGrowId: " + binaryen.TableGrowId); console.log("TryId: " + binaryen.TryId); + console.log("TryTableId: " + binaryen.TryTableId); console.log("ThrowId: " + binaryen.ThrowId); console.log("RethrowId: " + binaryen.RethrowId); + console.log("ThrowRefId: " + binaryen.ThrowRefId); console.log("TupleMakeId: " + binaryen.TupleMakeId); console.log("TupleExtractId: " + binaryen.TupleExtractId); console.log("RefI31Id: " + binaryen.RefI31Id); diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index e01e1a26160..e337841f3f7 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -88,8 +88,10 @@ TableSetId: 47 TableSizeId: 48 TableGrowId: 49 TryId: 54 +TryTableId: 55 ThrowId: 56 RethrowId: 57 +ThrowRefId: 58 TupleMakeId: 59 TupleExtractId: 60 RefI31Id: 61 diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index d0e40b94ae9..41f780c0bc7 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -1110,6 +1110,26 @@ void test_core() { nopCatchBody, 1, NULL), + // (block $catch_all_dest + // (try_table (catch_all $catch_all_dest) + // (throw $a-tag (i32.const 0)) + // ) + // ) + BinaryenBlock( + module, + "catch_all_dest", + (BinaryenExpressionRef[]){BinaryenTryTable( + module, + BinaryenThrow( + module, "a-tag", (BinaryenExpressionRef[]){makeInt32(module, 0)}, 1), + (const char*[]){NULL}, + (const char*[]){"catch_all_dest"}, + (bool[]){false}, + 1)}, + 1, + BinaryenTypeNone()), + // (throw_ref (ref.null noexn)) + BinaryenThrowRef(module, BinaryenRefNull(module, BinaryenHeapTypeNoexn())), // Atomics BinaryenAtomicStore( module, diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index eb293c3096a..1cb4b093a3d 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -2193,6 +2193,16 @@ BinaryenFeatureAll: 268435455 (nop) ) ) + (block $catch_all_dest + (try_table (catch_all $catch_all_dest) + (throw $a-tag + (i32.const 0) + ) + ) + ) + (throw_ref + (ref.null noexn) + ) (i32.atomic.store (i32.const 0) (i32.atomic.load