Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
Implement rudimentary support for TryFinally.
Browse files Browse the repository at this point in the history
Currently, it does not correctly handle `Labeled/Return` pairs that
cross its boundary.
  • Loading branch information
sjrd committed Mar 26, 2024
1 parent 2557861 commit 452ffec
Showing 1 changed file with 41 additions and 1 deletion.
42 changes: 41 additions & 1 deletion wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private class WasmExpressionBuilder private (
case t: IRTrees.If => genIf(t, expectedType)
case t: IRTrees.While => genWhile(t)
case t: IRTrees.TryCatch => genTryCatch(t)
case t: IRTrees.TryFinally => genTryFinally(t)
case t: IRTrees.Throw => genThrow(t)
case t: IRTrees.Debugger => IRTypes.NoType // ignore
case t: IRTrees.Skip => IRTypes.NoType
Expand Down Expand Up @@ -165,7 +166,6 @@ private class WasmExpressionBuilder private (
// case IRTrees.JSSuperMethodCall(pos) =>
// case IRTrees.Match(tpe) =>
// case IRTrees.RecordSelect(tpe) =>
// case IRTrees.TryFinally(pos) =>
// case IRTrees.JSImportMeta(pos) =>
// case IRTrees.JSSuperSelect(pos) =>
// case IRTrees.JSSuperConstructorCall(pos) =>
Expand Down Expand Up @@ -1346,6 +1346,46 @@ private class WasmExpressionBuilder private (
t.tpe
}

private def genTryFinally(t: IRTrees.TryFinally): IRTypes.Type = {
/* This implementation is rudimentary. It does not handle `Labeled/Return`
* pairs that cross its boundary. In case there is a `Return` inside the
* `try` block targeting a `Labeled` block around this `TryFinally`, the
* `finally` block is by-passed.
*/

val resultType = TypeTransformer.transformResultType(t.tpe)(ctx)
val resultLocals = resultType.map(fctx.addSyntheticLocal(_))

fctx.block() { doneLabel =>
fctx.block(Types.WasmExnRef) { catchLabel =>
fctx.tryTable()(List(CatchClause.CatchAllRef(catchLabel))) {
// try block
genTree(t.block, t.tpe)

// store the result in locals during the finally block
for (resultLocal <- resultLocals.reverse)
instrs += LOCAL_SET(resultLocal)
}

// on success, push a `null_ref exn` on the stack
instrs += REF_NULL(HeapType(Types.WasmHeapType.Simple.Exn))
} // end block $catch

// finally block (during which we leave the `(ref null exn)` on the stack)
genTree(t.finalizer, IRTypes.NoType)

// if the `exnref` is non-null, rethrow it
instrs += BR_ON_NULL(doneLabel)
instrs += THROW_REF
} // end block $done

// reload the result onto the stack
for (resultLocal <- resultLocals)
instrs += LOCAL_GET(resultLocal)

t.tpe
}

private def genThrow(tree: IRTrees.Throw): IRTypes.Type = {
genTree(tree.expr, IRTypes.AnyType)
instrs += THROW(TagIdx(ctx.exceptionTagName))
Expand Down

0 comments on commit 452ffec

Please sign in to comment.