From 5a8ceff02e46ef685437c8c8f4d3f2f53283699e Mon Sep 17 00:00:00 2001 From: BlobMaster41 <96896824+BlobMaster41@users.noreply.github.com> Date: Thu, 11 Dec 2025 00:16:27 -0500 Subject: [PATCH 1/3] Implement exception handling in compiler Adds support for compiling throw, try, catch, and finally statements using WebAssembly exception handling when the feature is enabled. Introduces logic to emit exception tags, throw, try, catch, and rethrow instructions, and provides fallback to abort() when exception handling is disabled. Includes new tests for exception handling. --- src/compiler.ts | 216 +- tests/compiler/exceptions.debug.wat | 3029 +++++++++++++++++++++++++ tests/compiler/exceptions.json | 3 + tests/compiler/exceptions.release.wat | 1909 ++++++++++++++++ tests/compiler/exceptions.ts | 110 + 5 files changed, 5257 insertions(+), 10 deletions(-) create mode 100644 tests/compiler/exceptions.debug.wat create mode 100644 tests/compiler/exceptions.json create mode 100644 tests/compiler/exceptions.release.wat create mode 100644 tests/compiler/exceptions.ts diff --git a/src/compiler.ts b/src/compiler.ts index f339e83aa9..e7f382fc5f 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -61,6 +61,8 @@ import { getConstValueInteger } from "./module"; +import * as binaryen from "./glue/binaryen"; + import { CommonFlags, STATIC_DELIMITER, @@ -479,6 +481,8 @@ export class Compiler extends DiagnosticEmitter { hasCustomFunctionExports: bool = false; /** Whether the module would use the exported runtime to lift/lower. */ desiresExportRuntime: bool = false; + /** Whether the exception tag has been created. */ + exceptionTagEnsured: bool = false; /** Compiles a {@link Program} to a {@link Module} using the specified options. */ static compile(program: Program): Module { @@ -3107,12 +3111,27 @@ export class Compiler extends DiagnosticEmitter { private compileThrowStatement( statement: ThrowStatement ): ExpressionRef { - // TODO: requires exception-handling spec. + let module = this.module; let flow = this.currentFlow; // Remember that this branch throws flow.set(FlowFlags.Throws | FlowFlags.Terminates); + // If exception handling feature is enabled, use actual throw instruction + if (this.options.hasFeature(Feature.ExceptionHandling)) { + let value = statement.value; + // Compile the thrown value - should be Error or subclass + let valueExpr = this.compileExpression(value, Type.auto); + let valueType = this.currentType; + + // Ensure exception tag exists + let tagName = this.ensureExceptionTag(); + + // Emit throw instruction with the error pointer + return module.throw(tagName, [valueExpr]); + } + + // Fallback: convert throw to abort() call when exception handling is disabled let stmts = new Array(); let value = statement.value; let message: Expression | null = null; @@ -3123,20 +3142,184 @@ export class Compiler extends DiagnosticEmitter { stmts.push( this.makeAbort(message, statement) ); - return this.module.flatten(stmts); + return module.flatten(stmts); } private compileTryStatement( statement: TryStatement ): ExpressionRef { - // TODO: can't yet support something like: try { return ... } finally { ... } - // worthwhile to investigate lowering returns to block results (here)? - this.error( - DiagnosticCode.Not_implemented_0, - statement.range, - "Exceptions" - ); - return this.module.unreachable(); + let module = this.module; + let outerFlow = this.currentFlow; + + // Check feature flag + if (!this.options.hasFeature(Feature.ExceptionHandling)) { + this.error( + DiagnosticCode.Feature_0_is_not_enabled, + statement.range, + "exception-handling" + ); + return module.unreachable(); + } + + // Ensure exception tag exists + let tagName = this.ensureExceptionTag(); + + // Generate unique label for this try block + let label = outerFlow.pushControlFlowLabel(); + let tryLabel = `try|${label}`; + + // Compile try block body + let tryFlow = outerFlow.fork(); + this.currentFlow = tryFlow; + let tryStmts = new Array(); + this.compileStatements(statement.bodyStatements, tryStmts); + let tryBodyExpr = module.flatten(tryStmts); + let tryFlowTerminates = tryFlow.isAny(FlowFlags.Terminates); + let tryFlowThrows = tryFlow.isAny(FlowFlags.Throws); + + let catchTags: string[] = []; + let catchBodies: ExpressionRef[] = []; + let catchFlow: Flow | null = null; + let catchFlowTerminates = false; + + // Compile catch clause if present + let catchStatements = statement.catchStatements; + let catchVariable = statement.catchVariable; + if (catchStatements) { + catchFlow = outerFlow.fork(); + this.currentFlow = catchFlow; + + let catchStmts = new Array(); + + // The pop instruction MUST be the very first instruction in the catch block + // WebAssembly requires this - we can't wrap it in local.tee or anything else + let popExpr = module.pop(this.options.sizeTypeRef); + + // If there's a catch variable, bind it to the popped exception value + if (catchVariable) { + let catchVarName = catchVariable.text; + // The exception value is a pointer to Error object + let errorClass = this.program.lookup(CommonNames.Error); + let errorType: Type; + if (errorClass && errorClass.kind == ElementKind.ClassPrototype) { + let resolved = this.resolver.resolveClass(errorClass, null); + errorType = resolved ? resolved.type : this.options.usizeType; + } else { + errorType = this.options.usizeType; // Fallback to usize if Error class not found + } + + // Create a scoped local for the catch variable + let catchLocal = catchFlow.addScopedLocal(catchVarName, errorType); + // Use direct local.set without shadow stack to ensure pop is first + catchStmts.push(binaryen._BinaryenLocalSet(module.ref, catchLocal.index, popExpr)); + // Mark the catch variable as initialized + catchFlow.setLocalFlag(catchLocal.index, LocalFlags.Initialized); + } else { + // No catch variable, but still need to pop the exception value + catchStmts.push(module.drop(popExpr)); + } + + // Compile catch block statements + this.compileStatements(catchStatements, catchStmts); + + catchTags.push(tagName); + catchBodies.push(module.flatten(catchStmts)); + catchFlowTerminates = catchFlow.isAny(FlowFlags.Terminates); + } + + // Handle finally clause if present + let finallyStatements = statement.finallyStatements; + if (finallyStatements) { + // Compile finally block statements (we'll use this in multiple places) + let finallyFlow = outerFlow.fork(); + this.currentFlow = finallyFlow; + let finallyStmts = new Array(); + this.compileStatements(finallyStatements, finallyStmts); + let finallyExpr = module.flatten(finallyStmts); + + outerFlow.popControlFlowLabel(label); + this.currentFlow = outerFlow; + + // For try-finally, we need to: + // 1. Wrap the try (and catch if present) in an outer try with catch_all + // 2. In catch_all: run finally, then rethrow + // 3. After the try: run finally for normal completion + + // Build the inner try-catch (if there's a catch clause) + let innerTryExpr: ExpressionRef; + if (catchBodies.length > 0) { + // We have a catch clause - wrap in try-catch + innerTryExpr = module.try(tryLabel, tryBodyExpr, catchTags, catchBodies, null); + } else { + // No catch clause - just the try body + innerTryExpr = tryBodyExpr; + } + + // Create the outer try with catch_all for finally+rethrow + // In Binaryen, catch_all is signaled by having one more catchBody than catchTags + // i.e., catchTags=[], catchBodies=[body] creates a catch_all + let outerTryLabel = `try_finally|${label}`; + let catchAllBody = module.block(null, [ + // Run finally code + finallyExpr, + // Rethrow the caught exception + module.rethrow(outerTryLabel) + ]); + + let outerTryExpr = module.try( + outerTryLabel, + innerTryExpr, + [], // No specific tags - the extra body becomes catch_all + [catchAllBody], // One body without a tag = catch_all + null + ); + + // Merge flow states + if (catchFlow) { + if (tryFlowTerminates && catchFlowTerminates) { + outerFlow.set(FlowFlags.Terminates); + } else { + outerFlow.inheritAlternatives(tryFlow, catchFlow); + } + } else { + // Only finally, no catch - exceptions propagate after finally + outerFlow.mergeSideEffects(tryFlow); + } + + // For normal completion: run the outer try, then finally + // We need to compile finally again for the normal path since finallyExpr was already used + finallyFlow = outerFlow.fork(); + this.currentFlow = finallyFlow; + let finallyStmts2 = new Array(); + this.compileStatements(finallyStatements, finallyStmts2); + let finallyExpr2 = module.flatten(finallyStmts2); + this.currentFlow = outerFlow; + + return module.block(null, [outerTryExpr, finallyExpr2]); + } + + // No finally clause + outerFlow.popControlFlowLabel(label); + this.currentFlow = outerFlow; + + // Merge flow states + if (catchFlow) { + if (tryFlowTerminates && catchFlowTerminates) { + outerFlow.set(FlowFlags.Terminates); + } else if (!catchStatements) { + // No catch, only try + outerFlow.inherit(tryFlow); + } else { + outerFlow.inheritAlternatives(tryFlow, catchFlow); + } + } + + // If no catch handlers, just return the try body (exceptions propagate) + if (catchBodies.length == 0) { + return tryBodyExpr; + } + + return module.try(tryLabel, tryBodyExpr, catchTags, catchBodies, null); } /** Compiles a variable statement. Returns `0` if an initializer is not necessary. */ @@ -6736,6 +6919,19 @@ export class Compiler extends DiagnosticEmitter { return name; } + /** Ensures the exception tag for exception handling exists. */ + ensureExceptionTag(): string { + let tagName = "$error"; + if (!this.exceptionTagEnsured) { + let module = this.module; + let sizeTypeRef = this.options.sizeTypeRef; + // Tag with single param: pointer to Error object + module.addTag(tagName, sizeTypeRef, TypeRef.None); + this.exceptionTagEnsured = true; + } + return tagName; + } + /** Ensures compilation of the varargs stub for the specified function. */ ensureVarargsStub(original: Function): Function { // A varargs stub is a function called with omitted arguments being zeroed, diff --git a/tests/compiler/exceptions.debug.wat b/tests/compiler/exceptions.debug.wat new file mode 100644 index 0000000000..1b61b11958 --- /dev/null +++ b/tests/compiler/exceptions.debug.wat @@ -0,0 +1,3029 @@ +(module + (type $0 (func (param i32 i32))) + (type $1 (func (param i32) (result i32))) + (type $2 (func (param i32))) + (type $3 (func)) + (type $4 (func (result i32))) + (type $5 (func (param i32 i32) (result i32))) + (type $6 (func (param i32 i32 i32))) + (type $7 (func (param i32 i32 i32 i32))) + (type $8 (func (param i32 i32 i64) (result i32))) + (type $9 (func (param i32 i32 i32 i32 i32) (result i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $~lib/rt/itcms/total (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/threshold (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/state (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/visitCount (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/pinSpace (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/iter (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/toSpace (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/white (mut i32) (i32.const 0)) + (global $~lib/shared/runtime/Runtime.Stub i32 (i32.const 0)) + (global $~lib/shared/runtime/Runtime.Minimal i32 (i32.const 1)) + (global $~lib/shared/runtime/Runtime.Incremental i32 (i32.const 2)) + (global $~lib/rt/itcms/fromSpace (mut i32) (i32.const 0)) + (global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0)) + (global $~lib/native/ASC_LOW_MEMORY_LIMIT i32 (i32.const 0)) + (global $~lib/native/ASC_SHRINK_LEVEL i32 (i32.const 0)) + (global $exceptions/finallyRan (mut i32) (i32.const 0)) + (global $exceptions/tryCatchFinallyRan (mut i32) (i32.const 0)) + (global $exceptions/tryCatchFinallyResult (mut i32) (i32.const 0)) + (global $exceptions/finallyWithExceptionRan (mut i32) (i32.const 0)) + (global $exceptions/finallyNormalRan (mut i32) (i32.const 0)) + (global $~lib/rt/__rtti_base i32 (i32.const 688)) + (global $~lib/memory/__data_end i32 (i32.const 712)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 33480)) + (global $~lib/memory/__heap_base i32 (i32.const 33480)) + (memory $0 1) + (data $0 (i32.const 12) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e\00\00\00\00\00") + (data $1 (i32.const 80) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $2 (i32.const 108) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00 \00\00\00~\00l\00i\00b\00/\00r\00t\00/\00i\00t\00c\00m\00s\00.\00t\00s\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $3 (i32.const 176) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $4 (i32.const 204) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00$\00\00\00I\00n\00d\00e\00x\00 \00o\00u\00t\00 \00o\00f\00 \00r\00a\00n\00g\00e\00\00\00\00\00\00\00\00\00") + (data $5 (i32.const 272) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $6 (i32.const 300) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00t\00l\00s\00f\00.\00t\00s\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $7 (i32.const 364) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00E\00r\00r\00o\00r\00\00\00") + (data $8 (i32.const 396) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $9 (i32.const 428) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\08\00\00\00o\00o\00p\00s\00\00\00\00\00") + (data $10 (i32.const 460) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1a\00\00\00e\00x\00c\00e\00p\00t\00i\00o\00n\00s\00.\00t\00s\00\00\00") + (data $11 (i32.const 508) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00m\00s\00g\00\00\00\00\00\00\00") + (data $12 (i32.const 540) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00i\00n\00n\00e\00r\00\00\00") + (data $13 (i32.const 572) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00o\00u\00t\00e\00r\00\00\00") + (data $14 (i32.const 604) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00e\00r\00r\00o\00r\00\00\00") + (data $15 (i32.const 636) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1c\00\00\00w\00i\00l\00l\00 \00p\00r\00o\00p\00a\00g\00a\00t\00e\00") + (data $16 (i32.const 688) "\05\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00") + (table $0 1 1 funcref) + (elem $0 (i32.const 1)) + (tag $$error (type $2) (param i32)) + (export "memory" (memory $0)) + (start $~start) + (func $~lib/rt/itcms/Object#set:nextWithColor (param $this i32) (param $nextWithColor i32) + local.get $this + local.get $nextWithColor + i32.store offset=4 + ) + (func $~lib/rt/itcms/Object#set:prev (param $this i32) (param $prev i32) + local.get $this + local.get $prev + i32.store offset=8 + ) + (func $~lib/rt/itcms/initLazy (param $space i32) (result i32) + local.get $space + local.get $space + call $~lib/rt/itcms/Object#set:nextWithColor + local.get $space + local.get $space + call $~lib/rt/itcms/Object#set:prev + local.get $space + return + ) + (func $~lib/rt/itcms/Object#get:nextWithColor (param $this i32) (result i32) + local.get $this + i32.load offset=4 + ) + (func $~lib/rt/itcms/Object#get:next (param $this i32) (result i32) + local.get $this + call $~lib/rt/itcms/Object#get:nextWithColor + i32.const 3 + i32.const -1 + i32.xor + i32.and + return + ) + (func $~lib/rt/itcms/Object#get:color (param $this i32) (result i32) + local.get $this + call $~lib/rt/itcms/Object#get:nextWithColor + i32.const 3 + i32.and + return + ) + (func $~lib/rt/itcms/visitRoots (param $cookie i32) + (local $pn i32) + (local $iter i32) + local.get $cookie + call $~lib/rt/__visit_globals + global.get $~lib/rt/itcms/pinSpace + local.set $pn + local.get $pn + call $~lib/rt/itcms/Object#get:next + local.set $iter + loop $while-continue|0 + local.get $iter + local.get $pn + i32.ne + if + i32.const 1 + drop + local.get $iter + call $~lib/rt/itcms/Object#get:color + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 128 + i32.const 160 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $iter + i32.const 20 + i32.add + local.get $cookie + call $~lib/rt/__visit_members + local.get $iter + call $~lib/rt/itcms/Object#get:next + local.set $iter + br $while-continue|0 + end + end + ) + (func $~lib/rt/itcms/Object#set:color (param $this i32) (param $color i32) + local.get $this + local.get $this + call $~lib/rt/itcms/Object#get:nextWithColor + i32.const 3 + i32.const -1 + i32.xor + i32.and + local.get $color + i32.or + call $~lib/rt/itcms/Object#set:nextWithColor + ) + (func $~lib/rt/itcms/Object#get:prev (param $this i32) (result i32) + local.get $this + i32.load offset=8 + ) + (func $~lib/rt/itcms/Object#set:next (param $this i32) (param $obj i32) + local.get $this + local.get $obj + local.get $this + call $~lib/rt/itcms/Object#get:nextWithColor + i32.const 3 + i32.and + i32.or + call $~lib/rt/itcms/Object#set:nextWithColor + ) + (func $~lib/rt/itcms/Object#unlink (param $this i32) + (local $next i32) + (local $prev i32) + local.get $this + call $~lib/rt/itcms/Object#get:next + local.set $next + local.get $next + i32.const 0 + i32.eq + if + i32.const 1 + drop + local.get $this + call $~lib/rt/itcms/Object#get:prev + i32.const 0 + i32.eq + if (result i32) + local.get $this + global.get $~lib/memory/__heap_base + i32.lt_u + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 128 + i32.const 128 + i32.const 18 + call $~lib/builtins/abort + unreachable + end + return + end + local.get $this + call $~lib/rt/itcms/Object#get:prev + local.set $prev + i32.const 1 + drop + local.get $prev + i32.eqz + if + i32.const 0 + i32.const 128 + i32.const 132 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $next + local.get $prev + call $~lib/rt/itcms/Object#set:prev + local.get $prev + local.get $next + call $~lib/rt/itcms/Object#set:next + ) + (func $~lib/rt/itcms/Object#get:rtId (param $this i32) (result i32) + local.get $this + i32.load offset=12 + ) + (func $~lib/shared/typeinfo/Typeinfo#get:flags (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $~lib/rt/__typeinfo (param $id i32) (result i32) + (local $ptr i32) + global.get $~lib/rt/__rtti_base + local.set $ptr + local.get $id + local.get $ptr + i32.load + i32.gt_u + if + i32.const 0 + i32.const 224 + call $~lib/error/Error#constructor + throw $$error + end + local.get $ptr + i32.const 4 + i32.add + local.get $id + i32.const 4 + i32.mul + i32.add + call $~lib/shared/typeinfo/Typeinfo#get:flags + return + ) + (func $~lib/rt/itcms/Object#get:isPointerfree (param $this i32) (result i32) + (local $rtId i32) + local.get $this + call $~lib/rt/itcms/Object#get:rtId + local.set $rtId + local.get $rtId + i32.const 2 + i32.le_u + if (result i32) + i32.const 1 + else + local.get $rtId + call $~lib/rt/__typeinfo + i32.const 32 + i32.and + i32.const 0 + i32.ne + end + return + ) + (func $~lib/rt/itcms/Object#linkTo (param $this i32) (param $list i32) (param $withColor i32) + (local $prev i32) + local.get $list + call $~lib/rt/itcms/Object#get:prev + local.set $prev + local.get $this + local.get $list + local.get $withColor + i32.or + call $~lib/rt/itcms/Object#set:nextWithColor + local.get $this + local.get $prev + call $~lib/rt/itcms/Object#set:prev + local.get $prev + local.get $this + call $~lib/rt/itcms/Object#set:next + local.get $list + local.get $this + call $~lib/rt/itcms/Object#set:prev + ) + (func $~lib/rt/itcms/Object#makeGray (param $this i32) + (local $1 i32) + local.get $this + global.get $~lib/rt/itcms/iter + i32.eq + if + local.get $this + call $~lib/rt/itcms/Object#get:prev + local.tee $1 + i32.eqz + if (result i32) + i32.const 0 + i32.const 128 + i32.const 148 + i32.const 30 + call $~lib/builtins/abort + unreachable + else + local.get $1 + end + global.set $~lib/rt/itcms/iter + end + local.get $this + call $~lib/rt/itcms/Object#unlink + local.get $this + global.get $~lib/rt/itcms/toSpace + local.get $this + call $~lib/rt/itcms/Object#get:isPointerfree + if (result i32) + global.get $~lib/rt/itcms/white + i32.eqz + else + i32.const 2 + end + call $~lib/rt/itcms/Object#linkTo + ) + (func $~lib/rt/itcms/__visit (param $ptr i32) (param $cookie i32) + (local $obj i32) + local.get $ptr + i32.eqz + if + return + end + local.get $ptr + i32.const 20 + i32.sub + local.set $obj + i32.const 0 + drop + local.get $obj + call $~lib/rt/itcms/Object#get:color + global.get $~lib/rt/itcms/white + i32.eq + if + local.get $obj + call $~lib/rt/itcms/Object#makeGray + global.get $~lib/rt/itcms/visitCount + i32.const 1 + i32.add + global.set $~lib/rt/itcms/visitCount + end + ) + (func $~lib/rt/itcms/visitStack (param $cookie i32) + (local $ptr i32) + global.get $~lib/memory/__stack_pointer + local.set $ptr + loop $while-continue|0 + local.get $ptr + global.get $~lib/memory/__heap_base + i32.lt_u + if + local.get $ptr + i32.load + local.get $cookie + call $~lib/rt/itcms/__visit + local.get $ptr + i32.const 4 + i32.add + local.set $ptr + br $while-continue|0 + end + end + ) + (func $~lib/rt/common/BLOCK#get:mmInfo (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $~lib/rt/itcms/Object#get:size (param $this i32) (result i32) + i32.const 4 + local.get $this + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + return + ) + (func $~lib/rt/tlsf/Root#set:flMap (param $this i32) (param $flMap i32) + local.get $this + local.get $flMap + i32.store + ) + (func $~lib/rt/common/BLOCK#set:mmInfo (param $this i32) (param $mmInfo i32) + local.get $this + local.get $mmInfo + i32.store + ) + (func $~lib/rt/tlsf/Block#set:prev (param $this i32) (param $prev i32) + local.get $this + local.get $prev + i32.store offset=4 + ) + (func $~lib/rt/tlsf/Block#set:next (param $this i32) (param $next i32) + local.get $this + local.get $next + i32.store offset=8 + ) + (func $~lib/rt/tlsf/Block#get:prev (param $this i32) (result i32) + local.get $this + i32.load offset=4 + ) + (func $~lib/rt/tlsf/Block#get:next (param $this i32) (result i32) + local.get $this + i32.load offset=8 + ) + (func $~lib/rt/tlsf/Root#get:flMap (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $~lib/rt/tlsf/removeBlock (param $root i32) (param $block i32) + (local $blockInfo i32) + (local $size i32) + (local $fl i32) + (local $sl i32) + (local $6 i32) + (local $7 i32) + (local $boundedSize i32) + (local $prev i32) + (local $next i32) + (local $root|11 i32) + (local $fl|12 i32) + (local $sl|13 i32) + (local $root|14 i32) + (local $fl|15 i32) + (local $sl|16 i32) + (local $head i32) + (local $root|18 i32) + (local $fl|19 i32) + (local $slMap i32) + (local $root|21 i32) + (local $fl|22 i32) + (local $slMap|23 i32) + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $blockInfo + i32.const 1 + drop + local.get $blockInfo + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 268 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $blockInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + local.set $size + i32.const 1 + drop + local.get $size + i32.const 12 + i32.ge_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 270 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $size + i32.const 256 + i32.lt_u + if + i32.const 0 + local.set $fl + local.get $size + i32.const 4 + i32.shr_u + local.set $sl + else + local.get $size + local.tee $6 + i32.const 1073741820 + local.tee $7 + local.get $6 + local.get $7 + i32.lt_u + select + local.set $boundedSize + i32.const 31 + local.get $boundedSize + i32.clz + i32.sub + local.set $fl + local.get $boundedSize + local.get $fl + i32.const 4 + i32.sub + i32.shr_u + i32.const 1 + i32.const 4 + i32.shl + i32.xor + local.set $sl + local.get $fl + i32.const 8 + i32.const 1 + i32.sub + i32.sub + local.set $fl + end + i32.const 1 + drop + local.get $fl + i32.const 23 + i32.lt_u + if (result i32) + local.get $sl + i32.const 16 + i32.lt_u + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 284 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $block + call $~lib/rt/tlsf/Block#get:prev + local.set $prev + local.get $block + call $~lib/rt/tlsf/Block#get:next + local.set $next + local.get $prev + if + local.get $prev + local.get $next + call $~lib/rt/tlsf/Block#set:next + end + local.get $next + if + local.get $next + local.get $prev + call $~lib/rt/tlsf/Block#set:prev + end + local.get $block + block $~lib/rt/tlsf/GETHEAD|inlined.0 (result i32) + local.get $root + local.set $root|11 + local.get $fl + local.set $fl|12 + local.get $sl + local.set $sl|13 + local.get $root|11 + local.get $fl|12 + i32.const 4 + i32.shl + local.get $sl|13 + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + br $~lib/rt/tlsf/GETHEAD|inlined.0 + end + i32.eq + if + local.get $root + local.set $root|14 + local.get $fl + local.set $fl|15 + local.get $sl + local.set $sl|16 + local.get $next + local.set $head + local.get $root|14 + local.get $fl|15 + i32.const 4 + i32.shl + local.get $sl|16 + i32.add + i32.const 2 + i32.shl + i32.add + local.get $head + i32.store offset=96 + local.get $next + i32.eqz + if + block $~lib/rt/tlsf/GETSL|inlined.0 (result i32) + local.get $root + local.set $root|18 + local.get $fl + local.set $fl|19 + local.get $root|18 + local.get $fl|19 + i32.const 2 + i32.shl + i32.add + i32.load offset=4 + br $~lib/rt/tlsf/GETSL|inlined.0 + end + local.set $slMap + local.get $root + local.set $root|21 + local.get $fl + local.set $fl|22 + local.get $slMap + i32.const 1 + local.get $sl + i32.shl + i32.const -1 + i32.xor + i32.and + local.tee $slMap + local.set $slMap|23 + local.get $root|21 + local.get $fl|22 + i32.const 2 + i32.shl + i32.add + local.get $slMap|23 + i32.store offset=4 + local.get $slMap + i32.eqz + if + local.get $root + local.get $root + call $~lib/rt/tlsf/Root#get:flMap + i32.const 1 + local.get $fl + i32.shl + i32.const -1 + i32.xor + i32.and + call $~lib/rt/tlsf/Root#set:flMap + end + end + end + ) + (func $~lib/rt/tlsf/insertBlock (param $root i32) (param $block i32) + (local $blockInfo i32) + (local $block|3 i32) + (local $right i32) + (local $rightInfo i32) + (local $block|6 i32) + (local $block|7 i32) + (local $left i32) + (local $leftInfo i32) + (local $size i32) + (local $fl i32) + (local $sl i32) + (local $13 i32) + (local $14 i32) + (local $boundedSize i32) + (local $root|16 i32) + (local $fl|17 i32) + (local $sl|18 i32) + (local $head i32) + (local $root|20 i32) + (local $fl|21 i32) + (local $sl|22 i32) + (local $head|23 i32) + (local $root|24 i32) + (local $fl|25 i32) + (local $root|26 i32) + (local $fl|27 i32) + (local $slMap i32) + i32.const 1 + drop + local.get $block + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 201 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $blockInfo + i32.const 1 + drop + local.get $blockInfo + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 203 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + block $~lib/rt/tlsf/GETRIGHT|inlined.0 (result i32) + local.get $block + local.set $block|3 + local.get $block|3 + i32.const 4 + i32.add + local.get $block|3 + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + br $~lib/rt/tlsf/GETRIGHT|inlined.0 + end + local.set $right + local.get $right + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $rightInfo + local.get $rightInfo + i32.const 1 + i32.and + if + local.get $root + local.get $right + call $~lib/rt/tlsf/removeBlock + local.get $block + local.get $blockInfo + i32.const 4 + i32.add + local.get $rightInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + local.tee $blockInfo + call $~lib/rt/common/BLOCK#set:mmInfo + block $~lib/rt/tlsf/GETRIGHT|inlined.1 (result i32) + local.get $block + local.set $block|6 + local.get $block|6 + i32.const 4 + i32.add + local.get $block|6 + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + br $~lib/rt/tlsf/GETRIGHT|inlined.1 + end + local.set $right + local.get $right + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $rightInfo + end + local.get $blockInfo + i32.const 2 + i32.and + if + block $~lib/rt/tlsf/GETFREELEFT|inlined.0 (result i32) + local.get $block + local.set $block|7 + local.get $block|7 + i32.const 4 + i32.sub + i32.load + br $~lib/rt/tlsf/GETFREELEFT|inlined.0 + end + local.set $left + local.get $left + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $leftInfo + i32.const 1 + drop + local.get $leftInfo + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 221 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $root + local.get $left + call $~lib/rt/tlsf/removeBlock + local.get $left + local.set $block + local.get $block + local.get $leftInfo + i32.const 4 + i32.add + local.get $blockInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + local.tee $blockInfo + call $~lib/rt/common/BLOCK#set:mmInfo + end + local.get $right + local.get $rightInfo + i32.const 2 + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $blockInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + local.set $size + i32.const 1 + drop + local.get $size + i32.const 12 + i32.ge_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 233 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + drop + local.get $block + i32.const 4 + i32.add + local.get $size + i32.add + local.get $right + i32.eq + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 234 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $right + i32.const 4 + i32.sub + local.get $block + i32.store + local.get $size + i32.const 256 + i32.lt_u + if + i32.const 0 + local.set $fl + local.get $size + i32.const 4 + i32.shr_u + local.set $sl + else + local.get $size + local.tee $13 + i32.const 1073741820 + local.tee $14 + local.get $13 + local.get $14 + i32.lt_u + select + local.set $boundedSize + i32.const 31 + local.get $boundedSize + i32.clz + i32.sub + local.set $fl + local.get $boundedSize + local.get $fl + i32.const 4 + i32.sub + i32.shr_u + i32.const 1 + i32.const 4 + i32.shl + i32.xor + local.set $sl + local.get $fl + i32.const 8 + i32.const 1 + i32.sub + i32.sub + local.set $fl + end + i32.const 1 + drop + local.get $fl + i32.const 23 + i32.lt_u + if (result i32) + local.get $sl + i32.const 16 + i32.lt_u + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 251 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + block $~lib/rt/tlsf/GETHEAD|inlined.1 (result i32) + local.get $root + local.set $root|16 + local.get $fl + local.set $fl|17 + local.get $sl + local.set $sl|18 + local.get $root|16 + local.get $fl|17 + i32.const 4 + i32.shl + local.get $sl|18 + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + br $~lib/rt/tlsf/GETHEAD|inlined.1 + end + local.set $head + local.get $block + i32.const 0 + call $~lib/rt/tlsf/Block#set:prev + local.get $block + local.get $head + call $~lib/rt/tlsf/Block#set:next + local.get $head + if + local.get $head + local.get $block + call $~lib/rt/tlsf/Block#set:prev + end + local.get $root + local.set $root|20 + local.get $fl + local.set $fl|21 + local.get $sl + local.set $sl|22 + local.get $block + local.set $head|23 + local.get $root|20 + local.get $fl|21 + i32.const 4 + i32.shl + local.get $sl|22 + i32.add + i32.const 2 + i32.shl + i32.add + local.get $head|23 + i32.store offset=96 + local.get $root + local.get $root + call $~lib/rt/tlsf/Root#get:flMap + i32.const 1 + local.get $fl + i32.shl + i32.or + call $~lib/rt/tlsf/Root#set:flMap + local.get $root + local.set $root|26 + local.get $fl + local.set $fl|27 + block $~lib/rt/tlsf/GETSL|inlined.1 (result i32) + local.get $root + local.set $root|24 + local.get $fl + local.set $fl|25 + local.get $root|24 + local.get $fl|25 + i32.const 2 + i32.shl + i32.add + i32.load offset=4 + br $~lib/rt/tlsf/GETSL|inlined.1 + end + i32.const 1 + local.get $sl + i32.shl + i32.or + local.set $slMap + local.get $root|26 + local.get $fl|27 + i32.const 2 + i32.shl + i32.add + local.get $slMap + i32.store offset=4 + ) + (func $~lib/rt/tlsf/addMemory (param $root i32) (param $start i32) (param $endU64 i64) (result i32) + (local $end i32) + (local $root|4 i32) + (local $tail i32) + (local $tailInfo i32) + (local $size i32) + (local $leftSize i32) + (local $left i32) + (local $root|10 i32) + (local $tail|11 i32) + local.get $endU64 + i32.wrap_i64 + local.set $end + i32.const 1 + drop + local.get $start + i64.extend_i32_u + local.get $endU64 + i64.le_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 382 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $start + i32.const 4 + i32.add + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + i32.const 4 + i32.sub + local.set $start + local.get $end + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.set $end + block $~lib/rt/tlsf/GETTAIL|inlined.0 (result i32) + local.get $root + local.set $root|4 + local.get $root|4 + i32.load offset=1568 + br $~lib/rt/tlsf/GETTAIL|inlined.0 + end + local.set $tail + i32.const 0 + local.set $tailInfo + local.get $tail + if + i32.const 1 + drop + local.get $start + local.get $tail + i32.const 4 + i32.add + i32.ge_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 389 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $start + i32.const 16 + i32.sub + local.get $tail + i32.eq + if + local.get $start + i32.const 16 + i32.sub + local.set $start + local.get $tail + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $tailInfo + else + end + else + i32.const 1 + drop + local.get $start + local.get $root + i32.const 1572 + i32.add + i32.ge_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 402 + i32.const 5 + call $~lib/builtins/abort + unreachable + end + end + local.get $end + local.get $start + i32.sub + local.set $size + local.get $size + i32.const 4 + i32.const 12 + i32.add + i32.const 4 + i32.add + i32.lt_u + if + i32.const 0 + return + end + local.get $size + i32.const 2 + i32.const 4 + i32.mul + i32.sub + local.set $leftSize + local.get $start + local.set $left + local.get $left + local.get $leftSize + i32.const 1 + i32.or + local.get $tailInfo + i32.const 2 + i32.and + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $left + i32.const 0 + call $~lib/rt/tlsf/Block#set:prev + local.get $left + i32.const 0 + call $~lib/rt/tlsf/Block#set:next + local.get $start + i32.const 4 + i32.add + local.get $leftSize + i32.add + local.set $tail + local.get $tail + i32.const 0 + i32.const 2 + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $root + local.set $root|10 + local.get $tail + local.set $tail|11 + local.get $root|10 + local.get $tail|11 + i32.store offset=1568 + local.get $root + local.get $left + call $~lib/rt/tlsf/insertBlock + i32.const 1 + return + ) + (func $~lib/rt/tlsf/initialize + (local $rootOffset i32) + (local $pagesBefore i32) + (local $pagesNeeded i32) + (local $root i32) + (local $root|4 i32) + (local $tail i32) + (local $fl i32) + (local $root|7 i32) + (local $fl|8 i32) + (local $slMap i32) + (local $sl i32) + (local $root|11 i32) + (local $fl|12 i32) + (local $sl|13 i32) + (local $head i32) + (local $memStart i32) + i32.const 0 + drop + global.get $~lib/memory/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.set $rootOffset + memory.size + local.set $pagesBefore + local.get $rootOffset + i32.const 1572 + i32.add + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $pagesNeeded + local.get $pagesNeeded + local.get $pagesBefore + i32.gt_s + if (result i32) + local.get $pagesNeeded + local.get $pagesBefore + i32.sub + memory.grow + i32.const 0 + i32.lt_s + else + i32.const 0 + end + if + unreachable + end + local.get $rootOffset + local.set $root + local.get $root + i32.const 0 + call $~lib/rt/tlsf/Root#set:flMap + local.get $root + local.set $root|4 + i32.const 0 + local.set $tail + local.get $root|4 + local.get $tail + i32.store offset=1568 + i32.const 0 + local.set $fl + loop $for-loop|0 + local.get $fl + i32.const 23 + i32.lt_u + if + local.get $root + local.set $root|7 + local.get $fl + local.set $fl|8 + i32.const 0 + local.set $slMap + local.get $root|7 + local.get $fl|8 + i32.const 2 + i32.shl + i32.add + local.get $slMap + i32.store offset=4 + i32.const 0 + local.set $sl + loop $for-loop|1 + local.get $sl + i32.const 16 + i32.lt_u + if + local.get $root + local.set $root|11 + local.get $fl + local.set $fl|12 + local.get $sl + local.set $sl|13 + i32.const 0 + local.set $head + local.get $root|11 + local.get $fl|12 + i32.const 4 + i32.shl + local.get $sl|13 + i32.add + i32.const 2 + i32.shl + i32.add + local.get $head + i32.store offset=96 + local.get $sl + i32.const 1 + i32.add + local.set $sl + br $for-loop|1 + end + end + local.get $fl + i32.const 1 + i32.add + local.set $fl + br $for-loop|0 + end + end + local.get $rootOffset + i32.const 1572 + i32.add + local.set $memStart + i32.const 0 + drop + local.get $root + local.get $memStart + memory.size + i64.extend_i32_s + i64.const 16 + i64.shl + call $~lib/rt/tlsf/addMemory + drop + local.get $root + global.set $~lib/rt/tlsf/ROOT + ) + (func $~lib/rt/tlsf/checkUsedBlock (param $ptr i32) (result i32) + (local $block i32) + local.get $ptr + i32.const 4 + i32.sub + local.set $block + local.get $ptr + i32.const 0 + i32.ne + if (result i32) + local.get $ptr + i32.const 15 + i32.and + i32.eqz + else + i32.const 0 + end + if (result i32) + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 1 + i32.and + i32.eqz + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 562 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $block + return + ) + (func $~lib/rt/tlsf/freeBlock (param $root i32) (param $block i32) + i32.const 0 + drop + local.get $block + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 1 + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $root + local.get $block + call $~lib/rt/tlsf/insertBlock + ) + (func $~lib/rt/tlsf/__free (param $ptr i32) + local.get $ptr + global.get $~lib/memory/__heap_base + i32.lt_u + if + return + end + global.get $~lib/rt/tlsf/ROOT + i32.eqz + if + call $~lib/rt/tlsf/initialize + end + global.get $~lib/rt/tlsf/ROOT + local.get $ptr + call $~lib/rt/tlsf/checkUsedBlock + call $~lib/rt/tlsf/freeBlock + ) + (func $~lib/rt/itcms/free (param $obj i32) + local.get $obj + global.get $~lib/memory/__heap_base + i32.lt_u + if + local.get $obj + i32.const 0 + call $~lib/rt/itcms/Object#set:nextWithColor + local.get $obj + i32.const 0 + call $~lib/rt/itcms/Object#set:prev + else + global.get $~lib/rt/itcms/total + local.get $obj + call $~lib/rt/itcms/Object#get:size + i32.sub + global.set $~lib/rt/itcms/total + i32.const 0 + drop + local.get $obj + i32.const 4 + i32.add + call $~lib/rt/tlsf/__free + end + ) + (func $~lib/rt/itcms/step (result i32) + (local $obj i32) + (local $1 i32) + (local $black i32) + (local $from i32) + block $break|0 + block $case2|0 + block $case1|0 + block $case0|0 + global.get $~lib/rt/itcms/state + local.set $1 + local.get $1 + i32.const 0 + i32.eq + br_if $case0|0 + local.get $1 + i32.const 1 + i32.eq + br_if $case1|0 + local.get $1 + i32.const 2 + i32.eq + br_if $case2|0 + br $break|0 + end + i32.const 1 + global.set $~lib/rt/itcms/state + i32.const 0 + global.set $~lib/rt/itcms/visitCount + i32.const 0 + call $~lib/rt/itcms/visitRoots + global.get $~lib/rt/itcms/toSpace + global.set $~lib/rt/itcms/iter + global.get $~lib/rt/itcms/visitCount + i32.const 1 + i32.mul + return + end + global.get $~lib/rt/itcms/white + i32.eqz + local.set $black + global.get $~lib/rt/itcms/iter + call $~lib/rt/itcms/Object#get:next + local.set $obj + loop $while-continue|1 + local.get $obj + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $obj + global.set $~lib/rt/itcms/iter + local.get $obj + call $~lib/rt/itcms/Object#get:color + local.get $black + i32.ne + if + local.get $obj + local.get $black + call $~lib/rt/itcms/Object#set:color + i32.const 0 + global.set $~lib/rt/itcms/visitCount + local.get $obj + i32.const 20 + i32.add + i32.const 0 + call $~lib/rt/__visit_members + global.get $~lib/rt/itcms/visitCount + i32.const 1 + i32.mul + return + end + local.get $obj + call $~lib/rt/itcms/Object#get:next + local.set $obj + br $while-continue|1 + end + end + i32.const 0 + global.set $~lib/rt/itcms/visitCount + i32.const 0 + call $~lib/rt/itcms/visitRoots + global.get $~lib/rt/itcms/iter + call $~lib/rt/itcms/Object#get:next + local.set $obj + local.get $obj + global.get $~lib/rt/itcms/toSpace + i32.eq + if + i32.const 0 + call $~lib/rt/itcms/visitStack + global.get $~lib/rt/itcms/iter + call $~lib/rt/itcms/Object#get:next + local.set $obj + loop $while-continue|2 + local.get $obj + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $obj + call $~lib/rt/itcms/Object#get:color + local.get $black + i32.ne + if + local.get $obj + local.get $black + call $~lib/rt/itcms/Object#set:color + local.get $obj + i32.const 20 + i32.add + i32.const 0 + call $~lib/rt/__visit_members + end + local.get $obj + call $~lib/rt/itcms/Object#get:next + local.set $obj + br $while-continue|2 + end + end + global.get $~lib/rt/itcms/fromSpace + local.set $from + global.get $~lib/rt/itcms/toSpace + global.set $~lib/rt/itcms/fromSpace + local.get $from + global.set $~lib/rt/itcms/toSpace + local.get $black + global.set $~lib/rt/itcms/white + local.get $from + call $~lib/rt/itcms/Object#get:next + global.set $~lib/rt/itcms/iter + i32.const 2 + global.set $~lib/rt/itcms/state + end + global.get $~lib/rt/itcms/visitCount + i32.const 1 + i32.mul + return + end + global.get $~lib/rt/itcms/iter + local.set $obj + local.get $obj + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $obj + call $~lib/rt/itcms/Object#get:next + global.set $~lib/rt/itcms/iter + i32.const 1 + drop + local.get $obj + call $~lib/rt/itcms/Object#get:color + global.get $~lib/rt/itcms/white + i32.eqz + i32.eq + i32.eqz + if + i32.const 0 + i32.const 128 + i32.const 229 + i32.const 20 + call $~lib/builtins/abort + unreachable + end + local.get $obj + call $~lib/rt/itcms/free + i32.const 10 + return + end + global.get $~lib/rt/itcms/toSpace + global.get $~lib/rt/itcms/toSpace + call $~lib/rt/itcms/Object#set:nextWithColor + global.get $~lib/rt/itcms/toSpace + global.get $~lib/rt/itcms/toSpace + call $~lib/rt/itcms/Object#set:prev + i32.const 0 + global.set $~lib/rt/itcms/state + br $break|0 + end + i32.const 0 + return + ) + (func $~lib/rt/itcms/interrupt + (local $budget i32) + i32.const 0 + drop + i32.const 0 + drop + i32.const 1024 + i32.const 200 + i32.mul + i32.const 100 + i32.div_u + local.set $budget + loop $do-loop|0 + local.get $budget + call $~lib/rt/itcms/step + i32.sub + local.set $budget + global.get $~lib/rt/itcms/state + i32.const 0 + i32.eq + if + i32.const 0 + drop + global.get $~lib/rt/itcms/total + i64.extend_i32_u + i32.const 200 + i64.extend_i32_u + i64.mul + i64.const 100 + i64.div_u + i32.wrap_i64 + i32.const 1024 + i32.add + global.set $~lib/rt/itcms/threshold + i32.const 0 + drop + return + end + local.get $budget + i32.const 0 + i32.gt_s + br_if $do-loop|0 + end + i32.const 0 + drop + global.get $~lib/rt/itcms/total + i32.const 1024 + global.get $~lib/rt/itcms/total + global.get $~lib/rt/itcms/threshold + i32.sub + i32.const 1024 + i32.lt_u + i32.mul + i32.add + global.set $~lib/rt/itcms/threshold + i32.const 0 + drop + ) + (func $~lib/rt/tlsf/computeSize (param $size i32) (result i32) + local.get $size + i32.const 12 + i32.le_u + if (result i32) + i32.const 12 + else + local.get $size + i32.const 4 + i32.add + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + i32.const 4 + i32.sub + end + return + ) + (func $~lib/rt/tlsf/prepareSize (param $size i32) (result i32) + local.get $size + i32.const 1073741820 + i32.gt_u + if + i32.const 0 + i32.const 32 + call $~lib/error/Error#constructor + throw $$error + end + local.get $size + call $~lib/rt/tlsf/computeSize + return + ) + (func $~lib/rt/tlsf/roundSize (param $size i32) (result i32) + local.get $size + i32.const 536870910 + i32.lt_u + if (result i32) + local.get $size + i32.const 1 + i32.const 27 + local.get $size + i32.clz + i32.sub + i32.shl + i32.add + i32.const 1 + i32.sub + else + local.get $size + end + return + ) + (func $~lib/rt/tlsf/searchBlock (param $root i32) (param $size i32) (result i32) + (local $fl i32) + (local $sl i32) + (local $requestSize i32) + (local $root|5 i32) + (local $fl|6 i32) + (local $slMap i32) + (local $head i32) + (local $flMap i32) + (local $root|10 i32) + (local $fl|11 i32) + (local $root|12 i32) + (local $fl|13 i32) + (local $sl|14 i32) + (local $root|15 i32) + (local $fl|16 i32) + (local $sl|17 i32) + local.get $size + i32.const 256 + i32.lt_u + if + i32.const 0 + local.set $fl + local.get $size + i32.const 4 + i32.shr_u + local.set $sl + else + local.get $size + call $~lib/rt/tlsf/roundSize + local.set $requestSize + i32.const 4 + i32.const 8 + i32.mul + i32.const 1 + i32.sub + local.get $requestSize + i32.clz + i32.sub + local.set $fl + local.get $requestSize + local.get $fl + i32.const 4 + i32.sub + i32.shr_u + i32.const 1 + i32.const 4 + i32.shl + i32.xor + local.set $sl + local.get $fl + i32.const 8 + i32.const 1 + i32.sub + i32.sub + local.set $fl + end + i32.const 1 + drop + local.get $fl + i32.const 23 + i32.lt_u + if (result i32) + local.get $sl + i32.const 16 + i32.lt_u + else + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 334 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + block $~lib/rt/tlsf/GETSL|inlined.2 (result i32) + local.get $root + local.set $root|5 + local.get $fl + local.set $fl|6 + local.get $root|5 + local.get $fl|6 + i32.const 2 + i32.shl + i32.add + i32.load offset=4 + br $~lib/rt/tlsf/GETSL|inlined.2 + end + i32.const 0 + i32.const -1 + i32.xor + local.get $sl + i32.shl + i32.and + local.set $slMap + i32.const 0 + local.set $head + local.get $slMap + i32.eqz + if + local.get $root + call $~lib/rt/tlsf/Root#get:flMap + i32.const 0 + i32.const -1 + i32.xor + local.get $fl + i32.const 1 + i32.add + i32.shl + i32.and + local.set $flMap + local.get $flMap + i32.eqz + if + i32.const 0 + local.set $head + else + local.get $flMap + i32.ctz + local.set $fl + block $~lib/rt/tlsf/GETSL|inlined.3 (result i32) + local.get $root + local.set $root|10 + local.get $fl + local.set $fl|11 + local.get $root|10 + local.get $fl|11 + i32.const 2 + i32.shl + i32.add + i32.load offset=4 + br $~lib/rt/tlsf/GETSL|inlined.3 + end + local.set $slMap + i32.const 1 + drop + local.get $slMap + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 347 + i32.const 18 + call $~lib/builtins/abort + unreachable + end + block $~lib/rt/tlsf/GETHEAD|inlined.2 (result i32) + local.get $root + local.set $root|12 + local.get $fl + local.set $fl|13 + local.get $slMap + i32.ctz + local.set $sl|14 + local.get $root|12 + local.get $fl|13 + i32.const 4 + i32.shl + local.get $sl|14 + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + br $~lib/rt/tlsf/GETHEAD|inlined.2 + end + local.set $head + end + else + block $~lib/rt/tlsf/GETHEAD|inlined.3 (result i32) + local.get $root + local.set $root|15 + local.get $fl + local.set $fl|16 + local.get $slMap + i32.ctz + local.set $sl|17 + local.get $root|15 + local.get $fl|16 + i32.const 4 + i32.shl + local.get $sl|17 + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + br $~lib/rt/tlsf/GETHEAD|inlined.3 + end + local.set $head + end + local.get $head + return + ) + (func $~lib/rt/tlsf/growMemory (param $root i32) (param $size i32) + (local $pagesBefore i32) + (local $root|3 i32) + (local $pagesNeeded i32) + (local $5 i32) + (local $6 i32) + (local $pagesWanted i32) + (local $pagesAfter i32) + i32.const 0 + drop + local.get $size + i32.const 256 + i32.ge_u + if + local.get $size + call $~lib/rt/tlsf/roundSize + local.set $size + end + memory.size + local.set $pagesBefore + local.get $size + i32.const 4 + local.get $pagesBefore + i32.const 16 + i32.shl + i32.const 4 + i32.sub + block $~lib/rt/tlsf/GETTAIL|inlined.1 (result i32) + local.get $root + local.set $root|3 + local.get $root|3 + i32.load offset=1568 + br $~lib/rt/tlsf/GETTAIL|inlined.1 + end + i32.ne + i32.shl + i32.add + local.set $size + local.get $size + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $pagesNeeded + local.get $pagesBefore + local.tee $5 + local.get $pagesNeeded + local.tee $6 + local.get $5 + local.get $6 + i32.gt_s + select + local.set $pagesWanted + local.get $pagesWanted + memory.grow + i32.const 0 + i32.lt_s + if + local.get $pagesNeeded + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + memory.size + local.set $pagesAfter + local.get $root + local.get $pagesBefore + i32.const 16 + i32.shl + local.get $pagesAfter + i64.extend_i32_s + i64.const 16 + i64.shl + call $~lib/rt/tlsf/addMemory + drop + ) + (func $~lib/rt/tlsf/prepareBlock (param $root i32) (param $block i32) (param $size i32) + (local $blockInfo i32) + (local $remaining i32) + (local $spare i32) + (local $block|6 i32) + (local $block|7 i32) + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + local.set $blockInfo + i32.const 1 + drop + local.get $size + i32.const 4 + i32.add + i32.const 15 + i32.and + i32.eqz + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 361 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $blockInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + local.get $size + i32.sub + local.set $remaining + local.get $remaining + i32.const 4 + i32.const 12 + i32.add + i32.ge_u + if + local.get $block + local.get $size + local.get $blockInfo + i32.const 2 + i32.and + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $block + i32.const 4 + i32.add + local.get $size + i32.add + local.set $spare + local.get $spare + local.get $remaining + i32.const 4 + i32.sub + i32.const 1 + i32.or + call $~lib/rt/common/BLOCK#set:mmInfo + local.get $root + local.get $spare + call $~lib/rt/tlsf/insertBlock + else + local.get $block + local.get $blockInfo + i32.const 1 + i32.const -1 + i32.xor + i32.and + call $~lib/rt/common/BLOCK#set:mmInfo + block $~lib/rt/tlsf/GETRIGHT|inlined.3 (result i32) + local.get $block + local.set $block|7 + local.get $block|7 + i32.const 4 + i32.add + local.get $block|7 + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + br $~lib/rt/tlsf/GETRIGHT|inlined.3 + end + block $~lib/rt/tlsf/GETRIGHT|inlined.2 (result i32) + local.get $block + local.set $block|6 + local.get $block|6 + i32.const 4 + i32.add + local.get $block|6 + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.add + br $~lib/rt/tlsf/GETRIGHT|inlined.2 + end + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 2 + i32.const -1 + i32.xor + i32.and + call $~lib/rt/common/BLOCK#set:mmInfo + end + ) + (func $~lib/rt/tlsf/allocateBlock (param $root i32) (param $size i32) (result i32) + (local $payloadSize i32) + (local $block i32) + local.get $size + call $~lib/rt/tlsf/prepareSize + local.set $payloadSize + local.get $root + local.get $payloadSize + call $~lib/rt/tlsf/searchBlock + local.set $block + local.get $block + i32.eqz + if + local.get $root + local.get $payloadSize + call $~lib/rt/tlsf/growMemory + local.get $root + local.get $payloadSize + call $~lib/rt/tlsf/searchBlock + local.set $block + i32.const 1 + drop + local.get $block + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 499 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + end + i32.const 1 + drop + local.get $block + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + local.get $payloadSize + i32.ge_u + i32.eqz + if + i32.const 0 + i32.const 320 + i32.const 501 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $root + local.get $block + call $~lib/rt/tlsf/removeBlock + local.get $root + local.get $block + local.get $payloadSize + call $~lib/rt/tlsf/prepareBlock + i32.const 0 + drop + local.get $block + return + ) + (func $~lib/rt/tlsf/__alloc (param $size i32) (result i32) + global.get $~lib/rt/tlsf/ROOT + i32.eqz + if + call $~lib/rt/tlsf/initialize + end + global.get $~lib/rt/tlsf/ROOT + local.get $size + call $~lib/rt/tlsf/allocateBlock + i32.const 4 + i32.add + return + ) + (func $~lib/rt/itcms/Object#set:rtId (param $this i32) (param $rtId i32) + local.get $this + local.get $rtId + i32.store offset=12 + ) + (func $~lib/rt/itcms/Object#set:rtSize (param $this i32) (param $rtSize i32) + local.get $this + local.get $rtSize + i32.store offset=16 + ) + (func $~lib/rt/itcms/__new (param $size i32) (param $id i32) (result i32) + (local $obj i32) + (local $ptr i32) + local.get $size + i32.const 1073741804 + i32.ge_u + if + i32.const 0 + i32.const 32 + call $~lib/error/Error#constructor + throw $$error + end + global.get $~lib/rt/itcms/total + global.get $~lib/rt/itcms/threshold + i32.ge_u + if + call $~lib/rt/itcms/interrupt + end + i32.const 16 + local.get $size + i32.add + call $~lib/rt/tlsf/__alloc + i32.const 4 + i32.sub + local.set $obj + local.get $obj + local.get $id + call $~lib/rt/itcms/Object#set:rtId + local.get $obj + local.get $size + call $~lib/rt/itcms/Object#set:rtSize + local.get $obj + global.get $~lib/rt/itcms/fromSpace + global.get $~lib/rt/itcms/white + call $~lib/rt/itcms/Object#linkTo + global.get $~lib/rt/itcms/total + local.get $obj + call $~lib/rt/itcms/Object#get:size + i32.add + global.set $~lib/rt/itcms/total + local.get $obj + i32.const 20 + i32.add + local.set $ptr + local.get $ptr + i32.const 0 + local.get $size + memory.fill + local.get $ptr + return + ) + (func $~lib/rt/itcms/__link (param $parentPtr i32) (param $childPtr i32) (param $expectMultiple i32) + (local $child i32) + (local $parent i32) + (local $parentColor i32) + local.get $childPtr + i32.eqz + if + return + end + i32.const 1 + drop + local.get $parentPtr + i32.eqz + if + i32.const 0 + i32.const 128 + i32.const 295 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $childPtr + i32.const 20 + i32.sub + local.set $child + local.get $child + call $~lib/rt/itcms/Object#get:color + global.get $~lib/rt/itcms/white + i32.eq + if + local.get $parentPtr + i32.const 20 + i32.sub + local.set $parent + local.get $parent + call $~lib/rt/itcms/Object#get:color + local.set $parentColor + local.get $parentColor + global.get $~lib/rt/itcms/white + i32.eqz + i32.eq + if + local.get $expectMultiple + if + local.get $parent + call $~lib/rt/itcms/Object#makeGray + else + local.get $child + call $~lib/rt/itcms/Object#makeGray + end + else + local.get $parentColor + i32.const 3 + i32.eq + if (result i32) + global.get $~lib/rt/itcms/state + i32.const 1 + i32.eq + else + i32.const 0 + end + if + local.get $child + call $~lib/rt/itcms/Object#makeGray + end + end + end + ) + (func $~lib/error/Error#set:message (param $this i32) (param $message i32) + local.get $this + local.get $message + i32.store offset=8 + local.get $this + local.get $message + i32.const 0 + call $~lib/rt/itcms/__link + ) + (func $~lib/error/Error#set:name (param $this i32) (param $name i32) + local.get $this + local.get $name + i32.store + local.get $this + local.get $name + i32.const 0 + call $~lib/rt/itcms/__link + ) + (func $~lib/error/Error#set:stack (param $this i32) (param $stack i32) + local.get $this + local.get $stack + i32.store offset=4 + local.get $this + local.get $stack + i32.const 0 + call $~lib/rt/itcms/__link + ) + (func $exceptions/testTryCatch (result i32) + (local $e i32) + try $try|0 + i32.const 0 + i32.const 448 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e + i32.const 1 + return + end + unreachable + ) + (func $~lib/error/Error#get:message (param $this i32) (result i32) + local.get $this + i32.load offset=8 + ) + (func $~lib/rt/common/OBJECT#get:rtSize (param $this i32) (result i32) + local.get $this + i32.load offset=16 + ) + (func $~lib/string/String#get:length (param $this i32) (result i32) + local.get $this + i32.const 20 + i32.sub + call $~lib/rt/common/OBJECT#get:rtSize + i32.const 1 + i32.shr_u + return + ) + (func $~lib/util/string/compareImpl (param $str1 i32) (param $index1 i32) (param $str2 i32) (param $index2 i32) (param $len i32) (result i32) + (local $ptr1 i32) + (local $ptr2 i32) + (local $7 i32) + (local $a i32) + (local $b i32) + local.get $str1 + local.get $index1 + i32.const 1 + i32.shl + i32.add + local.set $ptr1 + local.get $str2 + local.get $index2 + i32.const 1 + i32.shl + i32.add + local.set $ptr2 + i32.const 0 + i32.const 2 + i32.lt_s + drop + local.get $len + i32.const 4 + i32.ge_u + if (result i32) + local.get $ptr1 + i32.const 7 + i32.and + local.get $ptr2 + i32.const 7 + i32.and + i32.or + i32.eqz + else + i32.const 0 + end + if + block $do-break|0 + loop $do-loop|0 + local.get $ptr1 + i64.load + local.get $ptr2 + i64.load + i64.ne + if + br $do-break|0 + end + local.get $ptr1 + i32.const 8 + i32.add + local.set $ptr1 + local.get $ptr2 + i32.const 8 + i32.add + local.set $ptr2 + local.get $len + i32.const 4 + i32.sub + local.set $len + local.get $len + i32.const 4 + i32.ge_u + br_if $do-loop|0 + end + end + end + loop $while-continue|1 + local.get $len + local.tee $7 + i32.const 1 + i32.sub + local.set $len + local.get $7 + if + local.get $ptr1 + i32.load16_u + local.set $a + local.get $ptr2 + i32.load16_u + local.set $b + local.get $a + local.get $b + i32.ne + if + local.get $a + local.get $b + i32.sub + return + end + local.get $ptr1 + i32.const 2 + i32.add + local.set $ptr1 + local.get $ptr2 + i32.const 2 + i32.add + local.set $ptr2 + br $while-continue|1 + end + end + i32.const 0 + return + ) + (func $exceptions/testNoThrow (result i32) + (local $e i32) + try $try|0 + i32.const 1 + return + catch $$error + + local.set $e + i32.const 2 + return + end + unreachable + ) + (func $exceptions/testFinally + try $try_finally|0 + catch_all + i32.const 1 + global.set $exceptions/finallyRan + rethrow $try_finally|0 + end + i32.const 1 + global.set $exceptions/finallyRan + ) + (func $exceptions/testNested (result i32) + (local $e i32) + (local $e|1 i32) + try $try|0 + try $try|1 + i32.const 0 + i32.const 560 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e + i32.const 0 + i32.const 592 + call $~lib/error/Error#constructor + throw $$error + end + unreachable + catch $$error + + local.set $e|1 + i32.const 42 + return + end + unreachable + ) + (func $exceptions/testTryCatchFinally + (local $e i32) + try $try_finally|0 + try $try|0 + i32.const 0 + i32.const 624 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e + i32.const 10 + global.set $exceptions/tryCatchFinallyResult + end + catch_all + i32.const 1 + global.set $exceptions/tryCatchFinallyRan + rethrow $try_finally|0 + end + i32.const 1 + global.set $exceptions/tryCatchFinallyRan + ) + (func $exceptions/innerThrow + try $try_finally|0 + i32.const 0 + i32.const 656 + call $~lib/error/Error#constructor + throw $$error + catch_all + i32.const 1 + global.set $exceptions/finallyWithExceptionRan + rethrow $try_finally|0 + end + unreachable + ) + (func $exceptions/testFinallyWithException (result i32) + (local $e i32) + try $try|0 + call $exceptions/innerThrow + catch $$error + + local.set $e + global.get $exceptions/finallyWithExceptionRan + if (result i32) + i32.const 1 + else + i32.const 0 + end + return + end + i32.const 0 + return + ) + (func $exceptions/testFinallyNormalCompletion (result i32) + try $try_finally|0 + catch_all + i32.const 1 + global.set $exceptions/finallyNormalRan + rethrow $try_finally|0 + end + i32.const 1 + global.set $exceptions/finallyNormalRan + global.get $exceptions/finallyNormalRan + if (result i32) + i32.const 1 + else + i32.const 0 + end + return + ) + (func $~lib/rt/__visit_globals (param $0 i32) + (local $1 i32) + i32.const 224 + local.get $0 + call $~lib/rt/itcms/__visit + i32.const 32 + local.get $0 + call $~lib/rt/itcms/__visit + ) + (func $~lib/arraybuffer/ArrayBufferView~visit (param $0 i32) (param $1 i32) + (local $2 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + i32.load + local.get $1 + call $~lib/rt/itcms/__visit + ) + (func $~lib/object/Object~visit (param $0 i32) (param $1 i32) + ) + (func $~lib/error/Error~visit (param $0 i32) (param $1 i32) + (local $2 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + i32.load + local.get $1 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=4 + local.get $1 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=8 + local.get $1 + call $~lib/rt/itcms/__visit + ) + (func $~lib/rt/__visit_members (param $0 i32) (param $1 i32) + block $invalid + block $~lib/error/Error + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + block $~lib/object/Object + local.get $0 + i32.const 8 + i32.sub + i32.load + br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/error/Error $invalid + end + return + end + return + end + return + end + local.get $0 + local.get $1 + call $~lib/arraybuffer/ArrayBufferView~visit + return + end + local.get $0 + local.get $1 + call $~lib/error/Error~visit + return + end + unreachable + ) + (func $~start + call $start:exceptions + ) + (func $~stack_check + global.get $~lib/memory/__stack_pointer + global.get $~lib/memory/__data_end + i32.lt_s + if + i32.const 33504 + i32.const 33552 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~lib/error/Error#constructor (param $this i32) (param $message i32) (result i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.const 4 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + local.get $message + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=8 + local.get $2 + call $~lib/error/Error#set:message + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + i32.const 384 + call $~lib/error/Error#set:name + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + i32.const 416 + call $~lib/error/Error#set:stack + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + ) + (func $exceptions/testCatchVar (result i32) + (local $e i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + try $try|0 + i32.const 0 + i32.const 528 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e + local.get $e + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store + local.get $1 + call $~lib/error/Error#get:message + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + return + end + unreachable + ) + (func $~lib/string/String.__eq (param $left i32) (param $right i32) (result i32) + (local $leftLength i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $left + local.get $right + i32.eq + if + i32.const 1 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + i32.const 0 + i32.eq + if (result i32) + i32.const 1 + else + local.get $right + i32.const 0 + i32.eq + end + if + i32.const 0 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/string/String#get:length + local.set $leftLength + local.get $leftLength + local.get $right + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/string/String#get:length + i32.ne + if + i32.const 0 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + i32.const 0 + local.get $right + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=4 + local.get $3 + i32.const 0 + local.get $leftLength + call $~lib/util/string/compareImpl + i32.eqz + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + ) + (func $start:exceptions + (local $0 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + memory.size + i32.const 16 + i32.shl + global.get $~lib/memory/__heap_base + i32.sub + i32.const 1 + i32.shr_u + global.set $~lib/rt/itcms/threshold + i32.const 80 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/pinSpace + i32.const 176 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/toSpace + i32.const 272 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/fromSpace + call $exceptions/testTryCatch + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 15 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testCatchVar + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 528 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 26 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testNoThrow + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 36 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinally + global.get $exceptions/finallyRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 48 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testNested + i32.const 42 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 63 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testTryCatchFinally + global.get $exceptions/tryCatchFinallyResult + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 78 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/tryCatchFinallyRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 79 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinallyWithException + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 98 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinallyNormalCompletion + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 110 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) +) diff --git a/tests/compiler/exceptions.json b/tests/compiler/exceptions.json new file mode 100644 index 0000000000..bf3583d70c --- /dev/null +++ b/tests/compiler/exceptions.json @@ -0,0 +1,3 @@ +{ + "features": ["exception-handling"] +} diff --git a/tests/compiler/exceptions.release.wat b/tests/compiler/exceptions.release.wat new file mode 100644 index 0000000000..cd50a5b54d --- /dev/null +++ b/tests/compiler/exceptions.release.wat @@ -0,0 +1,1909 @@ +(module + (type $0 (func (param i32))) + (type $1 (func)) + (type $2 (func (param i32 i32))) + (type $3 (func (result i32))) + (type $4 (func (param i32) (result i32))) + (type $5 (func (param i32 i32 i32 i32))) + (type $6 (func (param i32 i32 i64))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (global $~lib/rt/itcms/total (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/threshold (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/state (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/visitCount (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/pinSpace (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/iter (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/toSpace (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/white (mut i32) (i32.const 0)) + (global $~lib/rt/itcms/fromSpace (mut i32) (i32.const 0)) + (global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0)) + (global $exceptions/tryCatchFinallyRan (mut i32) (i32.const 0)) + (global $exceptions/tryCatchFinallyResult (mut i32) (i32.const 0)) + (global $exceptions/finallyWithExceptionRan (mut i32) (i32.const 0)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34504)) + (memory $0 1) + (data $0 (i32.const 1036) "<") + (data $0.1 (i32.const 1048) "\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e") + (data $2 (i32.const 1132) "<") + (data $2.1 (i32.const 1144) "\02\00\00\00 \00\00\00~\00l\00i\00b\00/\00r\00t\00/\00i\00t\00c\00m\00s\00.\00t\00s") + (data $4 (i32.const 1228) "<") + (data $4.1 (i32.const 1240) "\02\00\00\00$\00\00\00I\00n\00d\00e\00x\00 \00o\00u\00t\00 \00o\00f\00 \00r\00a\00n\00g\00e") + (data $6 (i32.const 1324) "<") + (data $6.1 (i32.const 1336) "\02\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00t\00l\00s\00f\00.\00t\00s") + (data $7 (i32.const 1388) "\1c") + (data $7.1 (i32.const 1400) "\02\00\00\00\n\00\00\00E\00r\00r\00o\00r") + (data $8 (i32.const 1420) "\1c") + (data $8.1 (i32.const 1432) "\02") + (data $9 (i32.const 1452) "\1c") + (data $9.1 (i32.const 1464) "\02\00\00\00\08\00\00\00o\00o\00p\00s") + (data $10 (i32.const 1484) ",") + (data $10.1 (i32.const 1496) "\02\00\00\00\1a\00\00\00e\00x\00c\00e\00p\00t\00i\00o\00n\00s\00.\00t\00s") + (data $11 (i32.const 1532) "\1c") + (data $11.1 (i32.const 1544) "\02\00\00\00\06\00\00\00m\00s\00g") + (data $12 (i32.const 1564) "\1c") + (data $12.1 (i32.const 1576) "\02\00\00\00\n\00\00\00i\00n\00n\00e\00r") + (data $13 (i32.const 1596) "\1c") + (data $13.1 (i32.const 1608) "\02\00\00\00\n\00\00\00o\00u\00t\00e\00r") + (data $14 (i32.const 1628) "\1c") + (data $14.1 (i32.const 1640) "\02\00\00\00\n\00\00\00e\00r\00r\00o\00r") + (data $15 (i32.const 1660) ",") + (data $15.1 (i32.const 1672) "\02\00\00\00\1c\00\00\00w\00i\00l\00l\00 \00p\00r\00o\00p\00a\00g\00a\00t\00e") + (data $16 (i32.const 1712) "\05\00\00\00 \00\00\00 \00\00\00 ") + (tag $$error (type $0) (param i32)) + (export "memory" (memory $0)) + (start $~start) + (func $~lib/rt/itcms/visitRoots + (local $0 i32) + (local $1 i32) + i32.const 1248 + call $~lib/rt/itcms/__visit + i32.const 1056 + call $~lib/rt/itcms/__visit + global.get $~lib/rt/itcms/pinSpace + local.tee $1 + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + loop $while-continue|0 + local.get $0 + local.get $1 + i32.ne + if + local.get $0 + i32.load offset=4 + i32.const 3 + i32.and + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1152 + i32.const 160 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 20 + i32.add + call $~lib/rt/__visit_members + local.get $0 + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + br $while-continue|0 + end + end + ) + (func $~lib/rt/itcms/Object#makeGray (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + local.get $0 + global.get $~lib/rt/itcms/iter + i32.eq + if + local.get $0 + i32.load offset=8 + local.tee $1 + i32.eqz + if + i32.const 0 + i32.const 1152 + i32.const 148 + i32.const 30 + call $~lib/builtins/abort + unreachable + end + local.get $1 + global.set $~lib/rt/itcms/iter + end + block $__inlined_func$~lib/rt/itcms/Object#unlink$131 + local.get $0 + i32.load offset=4 + i32.const -4 + i32.and + local.tee $1 + i32.eqz + if + local.get $0 + i32.load offset=8 + i32.eqz + local.get $0 + i32.const 34504 + i32.lt_u + i32.and + i32.eqz + if + i32.const 0 + i32.const 1152 + i32.const 128 + i32.const 18 + call $~lib/builtins/abort + unreachable + end + br $__inlined_func$~lib/rt/itcms/Object#unlink$131 + end + local.get $0 + i32.load offset=8 + local.tee $2 + i32.eqz + if + i32.const 0 + i32.const 1152 + i32.const 132 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $1 + local.get $2 + i32.store offset=8 + local.get $2 + local.get $1 + local.get $2 + i32.load offset=4 + i32.const 3 + i32.and + i32.or + i32.store offset=4 + end + global.get $~lib/rt/itcms/toSpace + local.set $2 + local.get $0 + i32.load offset=12 + local.tee $1 + i32.const 2 + i32.le_u + if (result i32) + i32.const 1 + else + local.get $1 + i32.const 1712 + i32.load + i32.gt_u + if + i32.const 1248 + call $~lib/error/Error#constructor + throw $$error + end + local.get $1 + i32.const 2 + i32.shl + i32.const 1716 + i32.add + i32.load + i32.const 32 + i32.and + end + local.set $3 + local.get $2 + i32.load offset=8 + local.set $1 + local.get $0 + global.get $~lib/rt/itcms/white + i32.eqz + i32.const 2 + local.get $3 + select + local.get $2 + i32.or + i32.store offset=4 + local.get $0 + local.get $1 + i32.store offset=8 + local.get $1 + local.get $0 + local.get $1 + i32.load offset=4 + i32.const 3 + i32.and + i32.or + i32.store offset=4 + local.get $2 + local.get $0 + i32.store offset=8 + ) + (func $~lib/rt/itcms/__visit (param $0 i32) + local.get $0 + i32.eqz + if + return + end + global.get $~lib/rt/itcms/white + local.get $0 + i32.const 20 + i32.sub + local.tee $0 + i32.load offset=4 + i32.const 3 + i32.and + i32.eq + if + local.get $0 + call $~lib/rt/itcms/Object#makeGray + global.get $~lib/rt/itcms/visitCount + i32.const 1 + i32.add + global.set $~lib/rt/itcms/visitCount + end + ) + (func $~lib/rt/tlsf/removeBlock (param $0 i32) (param $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + local.get $1 + i32.load + local.tee $3 + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 268 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const -4 + i32.and + local.tee $3 + i32.const 12 + i32.lt_u + if + i32.const 0 + i32.const 1344 + i32.const 270 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $3 + i32.const 256 + i32.lt_u + if (result i32) + local.get $3 + i32.const 4 + i32.shr_u + else + i32.const 31 + i32.const 1073741820 + local.get $3 + local.get $3 + i32.const 1073741820 + i32.ge_u + select + local.tee $3 + i32.clz + i32.sub + local.tee $4 + i32.const 7 + i32.sub + local.set $2 + local.get $3 + local.get $4 + i32.const 4 + i32.sub + i32.shr_u + i32.const 16 + i32.xor + end + local.tee $3 + i32.const 16 + i32.lt_u + local.get $2 + i32.const 23 + i32.lt_u + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 284 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $1 + i32.load offset=8 + local.set $5 + local.get $1 + i32.load offset=4 + local.tee $4 + if + local.get $4 + local.get $5 + i32.store offset=8 + end + local.get $5 + if + local.get $5 + local.get $4 + i32.store offset=4 + end + local.get $1 + local.get $0 + local.get $2 + i32.const 4 + i32.shl + local.get $3 + i32.add + i32.const 2 + i32.shl + i32.add + local.tee $1 + i32.load offset=96 + i32.eq + if + local.get $1 + local.get $5 + i32.store offset=96 + local.get $5 + i32.eqz + if + local.get $0 + local.get $2 + i32.const 2 + i32.shl + i32.add + local.tee $1 + i32.load offset=4 + i32.const -2 + local.get $3 + i32.rotl + i32.and + local.set $3 + local.get $1 + local.get $3 + i32.store offset=4 + local.get $3 + i32.eqz + if + local.get $0 + local.get $0 + i32.load + i32.const -2 + local.get $2 + i32.rotl + i32.and + i32.store + end + end + end + ) + (func $~lib/rt/tlsf/insertBlock (param $0 i32) (param $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $1 + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 201 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $1 + i32.load + local.tee $3 + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 203 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $1 + i32.const 4 + i32.add + local.get $1 + i32.load + i32.const -4 + i32.and + i32.add + local.tee $4 + i32.load + local.tee $2 + i32.const 1 + i32.and + if + local.get $0 + local.get $4 + call $~lib/rt/tlsf/removeBlock + local.get $1 + local.get $3 + i32.const 4 + i32.add + local.get $2 + i32.const -4 + i32.and + i32.add + local.tee $3 + i32.store + local.get $1 + i32.const 4 + i32.add + local.get $1 + i32.load + i32.const -4 + i32.and + i32.add + local.tee $4 + i32.load + local.set $2 + end + local.get $3 + i32.const 2 + i32.and + if + local.get $1 + i32.const 4 + i32.sub + i32.load + local.tee $1 + i32.load + local.tee $6 + i32.const 1 + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 221 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $0 + local.get $1 + call $~lib/rt/tlsf/removeBlock + local.get $1 + local.get $6 + i32.const 4 + i32.add + local.get $3 + i32.const -4 + i32.and + i32.add + local.tee $3 + i32.store + end + local.get $4 + local.get $2 + i32.const 2 + i32.or + i32.store + local.get $3 + i32.const -4 + i32.and + local.tee $2 + i32.const 12 + i32.lt_u + if + i32.const 0 + i32.const 1344 + i32.const 233 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $4 + local.get $1 + i32.const 4 + i32.add + local.get $2 + i32.add + i32.ne + if + i32.const 0 + i32.const 1344 + i32.const 234 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $4 + i32.const 4 + i32.sub + local.get $1 + i32.store + local.get $2 + i32.const 256 + i32.lt_u + if (result i32) + local.get $2 + i32.const 4 + i32.shr_u + else + i32.const 31 + i32.const 1073741820 + local.get $2 + local.get $2 + i32.const 1073741820 + i32.ge_u + select + local.tee $2 + i32.clz + i32.sub + local.tee $3 + i32.const 7 + i32.sub + local.set $5 + local.get $2 + local.get $3 + i32.const 4 + i32.sub + i32.shr_u + i32.const 16 + i32.xor + end + local.tee $2 + i32.const 16 + i32.lt_u + local.get $5 + i32.const 23 + i32.lt_u + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 251 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $0 + local.get $5 + i32.const 4 + i32.shl + local.get $2 + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + local.set $3 + local.get $1 + i32.const 0 + i32.store offset=4 + local.get $1 + local.get $3 + i32.store offset=8 + local.get $3 + if + local.get $3 + local.get $1 + i32.store offset=4 + end + local.get $0 + local.get $5 + i32.const 4 + i32.shl + local.get $2 + i32.add + i32.const 2 + i32.shl + i32.add + local.get $1 + i32.store offset=96 + local.get $0 + local.get $0 + i32.load + i32.const 1 + local.get $5 + i32.shl + i32.or + i32.store + local.get $0 + local.get $5 + i32.const 2 + i32.shl + i32.add + local.tee $0 + local.get $0 + i32.load offset=4 + i32.const 1 + local.get $2 + i32.shl + i32.or + i32.store offset=4 + ) + (func $~lib/rt/tlsf/addMemory (param $0 i32) (param $1 i32) (param $2 i64) + (local $3 i32) + (local $4 i32) + (local $5 i32) + local.get $2 + local.get $1 + i64.extend_i32_u + i64.lt_u + if + i32.const 0 + i32.const 1344 + i32.const 382 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $1 + i32.const 19 + i32.add + i32.const -16 + i32.and + i32.const 4 + i32.sub + local.set $1 + local.get $0 + i32.load offset=1568 + local.tee $3 + if + local.get $3 + i32.const 4 + i32.add + local.get $1 + i32.gt_u + if + i32.const 0 + i32.const 1344 + i32.const 389 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + local.get $3 + local.get $1 + i32.const 16 + i32.sub + local.tee $5 + i32.eq + if + local.get $3 + i32.load + local.set $4 + local.get $5 + local.set $1 + end + else + local.get $0 + i32.const 1572 + i32.add + local.get $1 + i32.gt_u + if + i32.const 0 + i32.const 1344 + i32.const 402 + i32.const 5 + call $~lib/builtins/abort + unreachable + end + end + local.get $2 + i32.wrap_i64 + i32.const -16 + i32.and + local.get $1 + i32.sub + local.tee $3 + i32.const 20 + i32.lt_u + if + return + end + local.get $1 + local.get $4 + i32.const 2 + i32.and + local.get $3 + i32.const 8 + i32.sub + local.tee $3 + i32.const 1 + i32.or + i32.or + i32.store + local.get $1 + i32.const 0 + i32.store offset=4 + local.get $1 + i32.const 0 + i32.store offset=8 + local.get $1 + i32.const 4 + i32.add + local.get $3 + i32.add + local.tee $3 + i32.const 2 + i32.store + local.get $0 + local.get $3 + i32.store offset=1568 + local.get $0 + local.get $1 + call $~lib/rt/tlsf/insertBlock + ) + (func $~lib/rt/tlsf/initialize + (local $0 i32) + (local $1 i32) + memory.size + local.tee $1 + i32.const 0 + i32.le_s + if (result i32) + i32.const 1 + local.get $1 + i32.sub + memory.grow + i32.const 0 + i32.lt_s + else + i32.const 0 + end + if + unreachable + end + i32.const 34512 + i32.const 0 + i32.store + i32.const 36080 + i32.const 0 + i32.store + loop $for-loop|0 + local.get $0 + i32.const 23 + i32.lt_u + if + local.get $0 + i32.const 2 + i32.shl + i32.const 34512 + i32.add + i32.const 0 + i32.store offset=4 + i32.const 0 + local.set $1 + loop $for-loop|1 + local.get $1 + i32.const 16 + i32.lt_u + if + local.get $0 + i32.const 4 + i32.shl + local.get $1 + i32.add + i32.const 2 + i32.shl + i32.const 34512 + i32.add + i32.const 0 + i32.store offset=96 + local.get $1 + i32.const 1 + i32.add + local.set $1 + br $for-loop|1 + end + end + local.get $0 + i32.const 1 + i32.add + local.set $0 + br $for-loop|0 + end + end + i32.const 34512 + i32.const 36084 + memory.size + i64.extend_i32_s + i64.const 16 + i64.shl + call $~lib/rt/tlsf/addMemory + i32.const 34512 + global.set $~lib/rt/tlsf/ROOT + ) + (func $~lib/rt/itcms/step (result i32) + (local $0 i32) + (local $1 i32) + (local $2 i32) + block $break|0 + block $case2|0 + block $case1|0 + block $case0|0 + global.get $~lib/rt/itcms/state + br_table $case0|0 $case1|0 $case2|0 $break|0 + end + i32.const 1 + global.set $~lib/rt/itcms/state + i32.const 0 + global.set $~lib/rt/itcms/visitCount + call $~lib/rt/itcms/visitRoots + global.get $~lib/rt/itcms/toSpace + global.set $~lib/rt/itcms/iter + global.get $~lib/rt/itcms/visitCount + return + end + global.get $~lib/rt/itcms/white + i32.eqz + local.set $1 + global.get $~lib/rt/itcms/iter + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + loop $while-continue|1 + local.get $0 + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $0 + global.set $~lib/rt/itcms/iter + local.get $1 + local.get $0 + i32.load offset=4 + local.tee $2 + i32.const 3 + i32.and + i32.ne + if + local.get $0 + local.get $2 + i32.const -4 + i32.and + local.get $1 + i32.or + i32.store offset=4 + i32.const 0 + global.set $~lib/rt/itcms/visitCount + local.get $0 + i32.const 20 + i32.add + call $~lib/rt/__visit_members + global.get $~lib/rt/itcms/visitCount + return + end + local.get $0 + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + br $while-continue|1 + end + end + i32.const 0 + global.set $~lib/rt/itcms/visitCount + call $~lib/rt/itcms/visitRoots + global.get $~lib/rt/itcms/toSpace + global.get $~lib/rt/itcms/iter + i32.load offset=4 + i32.const -4 + i32.and + i32.eq + if + global.get $~lib/memory/__stack_pointer + local.set $0 + loop $while-continue|0 + local.get $0 + i32.const 34504 + i32.lt_u + if + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + local.get $0 + i32.const 4 + i32.add + local.set $0 + br $while-continue|0 + end + end + global.get $~lib/rt/itcms/iter + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + loop $while-continue|2 + local.get $0 + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $1 + local.get $0 + i32.load offset=4 + local.tee $2 + i32.const 3 + i32.and + i32.ne + if + local.get $0 + local.get $2 + i32.const -4 + i32.and + local.get $1 + i32.or + i32.store offset=4 + local.get $0 + i32.const 20 + i32.add + call $~lib/rt/__visit_members + end + local.get $0 + i32.load offset=4 + i32.const -4 + i32.and + local.set $0 + br $while-continue|2 + end + end + global.get $~lib/rt/itcms/fromSpace + local.set $0 + global.get $~lib/rt/itcms/toSpace + global.set $~lib/rt/itcms/fromSpace + local.get $0 + global.set $~lib/rt/itcms/toSpace + local.get $1 + global.set $~lib/rt/itcms/white + local.get $0 + i32.load offset=4 + i32.const -4 + i32.and + global.set $~lib/rt/itcms/iter + i32.const 2 + global.set $~lib/rt/itcms/state + end + global.get $~lib/rt/itcms/visitCount + return + end + global.get $~lib/rt/itcms/iter + local.tee $0 + global.get $~lib/rt/itcms/toSpace + i32.ne + if + local.get $0 + i32.load offset=4 + local.tee $1 + i32.const -4 + i32.and + global.set $~lib/rt/itcms/iter + global.get $~lib/rt/itcms/white + i32.eqz + local.get $1 + i32.const 3 + i32.and + i32.ne + if + i32.const 0 + i32.const 1152 + i32.const 229 + i32.const 20 + call $~lib/builtins/abort + unreachable + end + local.get $0 + i32.const 34504 + i32.lt_u + if + local.get $0 + i32.const 0 + i32.store offset=4 + local.get $0 + i32.const 0 + i32.store offset=8 + else + global.get $~lib/rt/itcms/total + local.get $0 + i32.load + i32.const -4 + i32.and + i32.const 4 + i32.add + i32.sub + global.set $~lib/rt/itcms/total + local.get $0 + i32.const 4 + i32.add + local.tee $0 + i32.const 34504 + i32.ge_u + if + global.get $~lib/rt/tlsf/ROOT + i32.eqz + if + call $~lib/rt/tlsf/initialize + end + global.get $~lib/rt/tlsf/ROOT + local.get $0 + i32.const 4 + i32.sub + local.set $2 + local.get $0 + i32.const 15 + i32.and + i32.const 1 + local.get $0 + select + if (result i32) + i32.const 1 + else + local.get $2 + i32.load + i32.const 1 + i32.and + end + if + i32.const 0 + i32.const 1344 + i32.const 562 + i32.const 3 + call $~lib/builtins/abort + unreachable + end + local.get $2 + local.get $2 + i32.load + i32.const 1 + i32.or + i32.store + local.get $2 + call $~lib/rt/tlsf/insertBlock + end + end + i32.const 10 + return + end + global.get $~lib/rt/itcms/toSpace + global.get $~lib/rt/itcms/toSpace + i32.store offset=4 + global.get $~lib/rt/itcms/toSpace + global.get $~lib/rt/itcms/toSpace + i32.store offset=8 + i32.const 0 + global.set $~lib/rt/itcms/state + end + i32.const 0 + ) + (func $~lib/rt/tlsf/searchBlock (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + local.get $0 + i32.load offset=4 + i32.const -2 + i32.and + local.tee $1 + if (result i32) + local.get $0 + local.get $1 + i32.ctz + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + else + local.get $0 + i32.load + i32.const -2 + i32.and + local.tee $1 + if (result i32) + local.get $0 + local.get $1 + i32.ctz + local.tee $2 + i32.const 2 + i32.shl + i32.add + i32.load offset=4 + local.tee $1 + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 347 + i32.const 18 + call $~lib/builtins/abort + unreachable + end + local.get $0 + local.get $1 + i32.ctz + local.get $2 + i32.const 4 + i32.shl + i32.add + i32.const 2 + i32.shl + i32.add + i32.load offset=96 + else + i32.const 0 + end + end + ) + (func $~lib/rt/itcms/__new (result i32) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + global.get $~lib/rt/itcms/total + global.get $~lib/rt/itcms/threshold + i32.ge_u + if + block $__inlined_func$~lib/rt/itcms/interrupt$69 + i32.const 2048 + local.set $0 + loop $do-loop|0 + local.get $0 + call $~lib/rt/itcms/step + i32.sub + local.set $0 + global.get $~lib/rt/itcms/state + i32.eqz + if + global.get $~lib/rt/itcms/total + i64.extend_i32_u + i64.const 200 + i64.mul + i64.const 100 + i64.div_u + i32.wrap_i64 + i32.const 1024 + i32.add + global.set $~lib/rt/itcms/threshold + br $__inlined_func$~lib/rt/itcms/interrupt$69 + end + local.get $0 + i32.const 0 + i32.gt_s + br_if $do-loop|0 + end + global.get $~lib/rt/itcms/total + global.get $~lib/rt/itcms/total + global.get $~lib/rt/itcms/threshold + i32.sub + i32.const 1024 + i32.lt_u + i32.const 10 + i32.shl + i32.add + global.set $~lib/rt/itcms/threshold + end + end + global.get $~lib/rt/tlsf/ROOT + i32.eqz + if + call $~lib/rt/tlsf/initialize + end + global.get $~lib/rt/tlsf/ROOT + local.tee $1 + call $~lib/rt/tlsf/searchBlock + local.tee $0 + i32.eqz + if + memory.size + local.tee $0 + i32.const 4 + local.get $1 + i32.load offset=1568 + local.get $0 + i32.const 16 + i32.shl + i32.const 4 + i32.sub + i32.ne + i32.shl + i32.const 65563 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $2 + local.get $0 + local.get $2 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $2 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + local.get $1 + local.get $0 + i32.const 16 + i32.shl + memory.size + i64.extend_i32_s + i64.const 16 + i64.shl + call $~lib/rt/tlsf/addMemory + local.get $1 + call $~lib/rt/tlsf/searchBlock + local.tee $0 + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 499 + i32.const 16 + call $~lib/builtins/abort + unreachable + end + end + local.get $0 + i32.load + i32.const -4 + i32.and + i32.const 28 + i32.lt_u + if + i32.const 0 + i32.const 1344 + i32.const 501 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $1 + local.get $0 + call $~lib/rt/tlsf/removeBlock + local.get $0 + i32.load + local.tee $2 + i32.const -4 + i32.and + i32.const 28 + i32.sub + local.tee $3 + i32.const 16 + i32.ge_u + if + local.get $0 + local.get $2 + i32.const 2 + i32.and + i32.const 28 + i32.or + i32.store + local.get $0 + i32.const 32 + i32.add + local.tee $2 + local.get $3 + i32.const 4 + i32.sub + i32.const 1 + i32.or + i32.store + local.get $1 + local.get $2 + call $~lib/rt/tlsf/insertBlock + else + local.get $0 + local.get $2 + i32.const -2 + i32.and + i32.store + local.get $0 + i32.const 4 + i32.add + local.get $0 + i32.load + i32.const -4 + i32.and + i32.add + local.tee $1 + local.get $1 + i32.load + i32.const -3 + i32.and + i32.store + end + local.get $0 + i32.const 4 + i32.store offset=12 + local.get $0 + i32.const 12 + i32.store offset=16 + global.get $~lib/rt/itcms/fromSpace + local.tee $1 + i32.load offset=8 + local.set $2 + local.get $0 + local.get $1 + global.get $~lib/rt/itcms/white + i32.or + i32.store offset=4 + local.get $0 + local.get $2 + i32.store offset=8 + local.get $2 + local.get $0 + local.get $2 + i32.load offset=4 + i32.const 3 + i32.and + i32.or + i32.store offset=4 + local.get $1 + local.get $0 + i32.store offset=8 + global.get $~lib/rt/itcms/total + local.get $0 + i32.load + i32.const -4 + i32.and + i32.const 4 + i32.add + i32.add + global.set $~lib/rt/itcms/total + local.get $0 + i32.const 20 + i32.add + local.tee $0 + i32.const 0 + i32.const 12 + memory.fill + local.get $0 + ) + (func $~lib/rt/itcms/__link (param $0 i32) (param $1 i32) + local.get $1 + i32.eqz + if + return + end + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 1152 + i32.const 295 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/rt/itcms/white + local.get $1 + i32.const 20 + i32.sub + local.tee $1 + i32.load offset=4 + i32.const 3 + i32.and + i32.eq + if + local.get $0 + i32.const 20 + i32.sub + i32.load offset=4 + i32.const 3 + i32.and + local.tee $0 + global.get $~lib/rt/itcms/white + i32.eqz + i32.eq + if + local.get $1 + call $~lib/rt/itcms/Object#makeGray + else + global.get $~lib/rt/itcms/state + i32.const 1 + i32.eq + local.get $0 + i32.const 3 + i32.eq + i32.and + if + local.get $1 + call $~lib/rt/itcms/Object#makeGray + end + end + end + ) + (func $~lib/rt/__visit_members (param $0 i32) + block $invalid + block $~lib/error/Error + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + block $~lib/object/Object + local.get $0 + i32.const 8 + i32.sub + i32.load + br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/error/Error $invalid + end + return + end + return + end + return + end + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + return + end + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=4 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=8 + call $~lib/rt/itcms/__visit + return + end + unreachable + ) + (func $~start + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1736 + i32.lt_s + if + i32.const 34528 + i32.const 34576 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + memory.size + i32.const 16 + i32.shl + i32.const 34504 + i32.sub + i32.const 1 + i32.shr_u + global.set $~lib/rt/itcms/threshold + i32.const 1108 + i32.const 1104 + i32.store + i32.const 1112 + i32.const 1104 + i32.store + i32.const 1104 + global.set $~lib/rt/itcms/pinSpace + i32.const 1204 + i32.const 1200 + i32.store + i32.const 1208 + i32.const 1200 + i32.store + i32.const 1200 + global.set $~lib/rt/itcms/toSpace + i32.const 1300 + i32.const 1296 + i32.store + i32.const 1304 + i32.const 1296 + i32.store + i32.const 1296 + global.set $~lib/rt/itcms/fromSpace + block $__inlined_func$exceptions/testTryCatch$121 + try + i32.const 1472 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + drop + br $__inlined_func$exceptions/testTryCatch$121 + end + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1736 + i32.lt_s + if + i32.const 34528 + i32.const 34576 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + block $__inlined_func$exceptions/testCatchVar$122 + try + i32.const 1552 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.load offset=8 + local.set $5 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + br $__inlined_func$exceptions/testCatchVar$122 + end + unreachable + end + global.get $~lib/memory/__stack_pointer + local.get $5 + i32.store + block $__inlined_func$~lib/string/String.__eq$1 (result i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1736 + i32.lt_s + if + i32.const 34528 + i32.const 34576 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $5 + i32.const 1552 + i32.eq + if + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + i32.const 1 + br $__inlined_func$~lib/string/String.__eq$1 + end + block $folding-inner0 + local.get $5 + i32.eqz + br_if $folding-inner0 + global.get $~lib/memory/__stack_pointer + local.get $5 + i32.store + local.get $5 + i32.const 20 + i32.sub + i32.load offset=16 + i32.const 1 + i32.shr_u + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 1552 + i32.store + local.get $1 + i32.const 1548 + i32.load + i32.const 1 + i32.shr_u + i32.ne + br_if $folding-inner0 + global.get $~lib/memory/__stack_pointer + local.get $5 + i32.store + i32.const 1552 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 1552 + i32.store offset=4 + i32.const 1 + local.get $5 + i32.const 7 + i32.and + local.get $1 + i32.const 4 + i32.lt_u + select + i32.eqz + if + loop $do-loop|0 + local.get $5 + i64.load + local.get $3 + i64.load + i64.eq + if + local.get $5 + i32.const 8 + i32.add + local.set $5 + local.get $3 + i32.const 8 + i32.add + local.set $3 + local.get $1 + i32.const 4 + i32.sub + local.tee $1 + i32.const 4 + i32.ge_u + br_if $do-loop|0 + end + end + end + block $__inlined_func$~lib/util/string/compareImpl$85 + loop $while-continue|1 + local.get $1 + local.tee $0 + i32.const 1 + i32.sub + local.set $1 + local.get $0 + if + local.get $5 + i32.load16_u + local.tee $2 + local.get $3 + i32.load16_u + local.tee $0 + i32.sub + local.set $4 + local.get $0 + local.get $2 + i32.ne + br_if $__inlined_func$~lib/util/string/compareImpl$85 + local.get $5 + i32.const 2 + i32.add + local.set $5 + local.get $3 + i32.const 2 + i32.add + local.set $3 + br $while-continue|1 + end + end + i32.const 0 + local.set $4 + end + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + i32.eqz + br $__inlined_func$~lib/string/String.__eq$1 + end + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + i32.const 0 + end + i32.eqz + if + i32.const 0 + i32.const 1504 + i32.const 26 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + block $__inlined_func$exceptions/testNested$125 + try + try + i32.const 1584 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + drop + i32.const 1616 + call $~lib/error/Error#constructor + throw $$error + end + unreachable + catch $$error + + drop + br $__inlined_func$exceptions/testNested$125 + end + unreachable + end + try $try_finally|07 + try + i32.const 1648 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + drop + i32.const 10 + global.set $exceptions/tryCatchFinallyResult + end + catch_all + i32.const 1 + global.set $exceptions/tryCatchFinallyRan + rethrow $try_finally|07 + end + i32.const 1 + global.set $exceptions/tryCatchFinallyRan + global.get $exceptions/tryCatchFinallyResult + i32.const 10 + i32.ne + if + i32.const 0 + i32.const 1504 + i32.const 78 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/tryCatchFinallyRan + i32.const 1 + i32.ne + if + i32.const 0 + i32.const 1504 + i32.const 79 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + block $__inlined_func$exceptions/testFinallyWithException$127 + try + try $try_finally|010 + i32.const 1680 + call $~lib/error/Error#constructor + throw $$error + catch_all + i32.const 1 + global.set $exceptions/finallyWithExceptionRan + rethrow $try_finally|010 + end + unreachable + catch $$error + + drop + global.get $exceptions/finallyWithExceptionRan + i32.const 0 + i32.ne + local.set $0 + br $__inlined_func$exceptions/testFinallyWithException$127 + end + unreachable + end + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 1504 + i32.const 98 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $~lib/error/Error#constructor (param $0 i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1736 + i32.lt_s + if + i32.const 34528 + i32.const 34576 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + global.get $~lib/memory/__stack_pointer + call $~lib/rt/itcms/__new + local.tee $1 + i32.store + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store offset=8 + local.get $1 + local.get $0 + i32.store offset=8 + local.get $1 + local.get $0 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 1408 + i32.store + local.get $1 + i32.const 1408 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 1440 + i32.store offset=4 + local.get $1 + i32.const 1440 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) +) diff --git a/tests/compiler/exceptions.ts b/tests/compiler/exceptions.ts new file mode 100644 index 0000000000..e0c0e70421 --- /dev/null +++ b/tests/compiler/exceptions.ts @@ -0,0 +1,110 @@ +// Basic throw +function testThrow(): void { + throw new Error("test"); +} + +// Try-catch basic +function testTryCatch(): i32 { + try { + throw new Error("oops"); + } catch (e) { + return 1; + } + return 0; +} +assert(testTryCatch() == 1); + +// Catch variable access +function testCatchVar(): string { + try { + throw new Error("msg"); + } catch (e) { + return e.message; + } + return ""; +} +assert(testCatchVar() == "msg"); + +// No exception thrown +function testNoThrow(): i32 { + try { + return 1; + } catch (e) { + return 2; + } +} +assert(testNoThrow() == 1); + +// Finally basic +let finallyRan = false; +function testFinally(): void { + try { + // normal completion + } finally { + finallyRan = true; + } +} +testFinally(); +assert(finallyRan == true); + +// Nested try-catch +function testNested(): i32 { + try { + try { + throw new Error("inner"); + } catch (e) { + throw new Error("outer"); + } + } catch (e) { + return 42; + } + return 0; +} +assert(testNested() == 42); + +// Try-catch-finally (without return in catch) +let tryCatchFinallyRan = false; +let tryCatchFinallyResult = 0; +function testTryCatchFinally(): void { + try { + throw new Error("error"); + } catch (e) { + tryCatchFinallyResult = 10; + } finally { + tryCatchFinallyRan = true; + } +} +testTryCatchFinally(); +assert(tryCatchFinallyResult == 10); +assert(tryCatchFinallyRan == true); + +// Finally with exception propagation +let finallyWithExceptionRan = false; +function innerThrow(): void { + try { + throw new Error("will propagate"); + } finally { + finallyWithExceptionRan = true; + } +} +function testFinallyWithException(): i32 { + try { + innerThrow(); + } catch (e) { + return finallyWithExceptionRan ? 1 : 0; + } + return 0; +} +assert(testFinallyWithException() == 1); + +// Try-finally with normal completion (no exception) +let finallyNormalRan = false; +function testFinallyNormalCompletion(): i32 { + try { + // no exception + } finally { + finallyNormalRan = true; + } + return finallyNormalRan ? 1 : 0; +} +assert(testFinallyNormalCompletion() == 1); From 54044583e08d5e01bea42a0668277a349f92ef02 Mon Sep 17 00:00:00 2001 From: BlobMaster41 <96896824+BlobMaster41@users.noreply.github.com> Date: Thu, 11 Dec 2025 00:26:29 -0500 Subject: [PATCH 2/3] Implement deferred return handling in try-finally Adds support for deferring return statements until after finally blocks in try-finally constructs. This is achieved by tracking pending actions and values in dedicated locals and dispatching control flow after finally execution. Updates flow context and test cases to verify correct behavior for returns in try-finally and try-catch-finally scenarios. --- src/compiler.ts | 209 +- src/flow.ts | 23 + tests/compiler/exceptions.debug.wat | 3542 ++++++++++++++++++++++--- tests/compiler/exceptions.release.wat | 698 +++-- tests/compiler/exceptions.ts | 353 +++ 5 files changed, 4281 insertions(+), 544 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index e7f382fc5f..4f1cee5026 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2966,6 +2966,28 @@ export class Compiler extends DiagnosticEmitter { // Remember that this flow returns flow.set(FlowFlags.Returns | FlowFlags.Terminates); + // Handle try-finally context: defer return until after finally + let tryFinallyContext = flow.getTryFinallyContext(); + if (tryFinallyContext) { + let pendingActionLocal = tryFinallyContext.tryFinallyPendingActionLocal; + let pendingValueLocal = tryFinallyContext.tryFinallyPendingValueLocal; + let dispatchLabel = assert(tryFinallyContext.tryFinallyDispatchLabel); + let stmts = new Array(); + + // Store return value if any + if (expr && returnType != Type.void) { + stmts.push(module.local_set(pendingValueLocal, expr, returnType.isManaged)); + } + + // Set pending action to RETURN (1) + stmts.push(module.local_set(pendingActionLocal, module.i32(1), false)); + + // Branch to finally dispatch + stmts.push(module.br(dispatchLabel)); + + return module.flatten(stmts); + } + // Handle inline return if (flow.isInline) { let inlineReturnLabel = assert(flow.inlineReturnLabel); @@ -3230,50 +3252,181 @@ export class Compiler extends DiagnosticEmitter { // Handle finally clause if present let finallyStatements = statement.finallyStatements; if (finallyStatements) { - // Compile finally block statements (we'll use this in multiple places) - let finallyFlow = outerFlow.fork(); - this.currentFlow = finallyFlow; - let finallyStmts = new Array(); - this.compileStatements(finallyStatements, finallyStmts); - let finallyExpr = module.flatten(finallyStmts); + // Set up pending action pattern for deferred control flow + // pendingAction: 0=normal, 1=return, 2=break, 3=continue + let returnType = outerFlow.returnType; + let targetFunction = outerFlow.targetFunction; + + // Create locals for pending action tracking + let pendingActionLocal = targetFunction.addLocal(Type.i32); + let pendingValueLocal: Local | null = returnType != Type.void + ? targetFunction.addLocal(returnType) + : null; + let pendingValueLocalIndex = pendingValueLocal ? pendingValueLocal.index : -1; + + // Create labels + let dispatchLabel = `finally_dispatch|${label}`; + let outerTryLabel = `try_finally|${label}`; + // Set up try-finally context on the flows BEFORE compiling try/catch bodies + // We need to recompile try and catch with the context set outerFlow.popControlFlowLabel(label); - this.currentFlow = outerFlow; - // For try-finally, we need to: - // 1. Wrap the try (and catch if present) in an outer try with catch_all - // 2. In catch_all: run finally, then rethrow - // 3. After the try: run finally for normal completion + // Re-fork flows with try-finally context + let label2 = outerFlow.pushControlFlowLabel(); + tryLabel = `try|${label2}`; + + tryFlow = outerFlow.fork(); + tryFlow.tryFinallyPendingActionLocal = pendingActionLocal.index; + tryFlow.tryFinallyPendingValueLocal = pendingValueLocalIndex; + tryFlow.tryFinallyDispatchLabel = dispatchLabel; + tryFlow.tryFinallyReturnType = returnType; + + this.currentFlow = tryFlow; + let tryStmts2 = new Array(); + this.compileStatements(statement.bodyStatements, tryStmts2); + tryBodyExpr = module.flatten(tryStmts2); + tryFlowTerminates = tryFlow.isAny(FlowFlags.Terminates); + + // Recompile catch with context if present + catchTags = []; + catchBodies = []; + catchFlow = null; + catchFlowTerminates = false; + + if (catchStatements) { + catchFlow = outerFlow.fork(); + catchFlow.tryFinallyPendingActionLocal = pendingActionLocal.index; + catchFlow.tryFinallyPendingValueLocal = pendingValueLocalIndex; + catchFlow.tryFinallyDispatchLabel = dispatchLabel; + catchFlow.tryFinallyReturnType = returnType; + + this.currentFlow = catchFlow; + + let catchStmts2 = new Array(); + let popExpr = module.pop(this.options.sizeTypeRef); + + if (catchVariable) { + let catchVarName = catchVariable.text; + let errorClass = this.program.lookup(CommonNames.Error); + let errorType: Type; + if (errorClass && errorClass.kind == ElementKind.ClassPrototype) { + let resolved = this.resolver.resolveClass(errorClass, null); + errorType = resolved ? resolved.type : this.options.usizeType; + } else { + errorType = this.options.usizeType; + } + let catchLocal = catchFlow.addScopedLocal(catchVarName, errorType); + catchStmts2.push(binaryen._BinaryenLocalSet(module.ref, catchLocal.index, popExpr)); + catchFlow.setLocalFlag(catchLocal.index, LocalFlags.Initialized); + } else { + catchStmts2.push(module.drop(popExpr)); + } + + this.compileStatements(catchStatements, catchStmts2); + + catchTags.push(tagName); + catchBodies.push(module.flatten(catchStmts2)); + catchFlowTerminates = catchFlow.isAny(FlowFlags.Terminates); + } + + this.currentFlow = outerFlow; // Build the inner try-catch (if there's a catch clause) let innerTryExpr: ExpressionRef; if (catchBodies.length > 0) { - // We have a catch clause - wrap in try-catch innerTryExpr = module.try(tryLabel, tryBodyExpr, catchTags, catchBodies, null); } else { - // No catch clause - just the try body innerTryExpr = tryBodyExpr; } - // Create the outer try with catch_all for finally+rethrow - // In Binaryen, catch_all is signaled by having one more catchBody than catchTags - // i.e., catchTags=[], catchBodies=[body] creates a catch_all - let outerTryLabel = `try_finally|${label}`; + // Compile finally statements for the catch_all path (exception handling) + let finallyFlow1 = outerFlow.fork(); + this.currentFlow = finallyFlow1; + let finallyStmts1 = new Array(); + this.compileStatements(finallyStatements, finallyStmts1); + let finallyExpr1 = module.flatten(finallyStmts1); + + // Create catch_all body: run finally, then rethrow let catchAllBody = module.block(null, [ - // Run finally code - finallyExpr, - // Rethrow the caught exception + finallyExpr1, module.rethrow(outerTryLabel) ]); + // Outer try with catch_all for exception path let outerTryExpr = module.try( outerTryLabel, innerTryExpr, - [], // No specific tags - the extra body becomes catch_all - [catchAllBody], // One body without a tag = catch_all + [], + [catchAllBody], null ); + // Compile finally statements for the normal/deferred path + let finallyFlow2 = outerFlow.fork(); + this.currentFlow = finallyFlow2; + let finallyStmts2 = new Array(); + this.compileStatements(finallyStatements, finallyStmts2); + let finallyExpr2 = module.flatten(finallyStmts2); + + this.currentFlow = outerFlow; + outerFlow.popControlFlowLabel(label2); + + // Build the dispatch logic after finally + let dispatchStmts = new Array(); + + // Run finally code + dispatchStmts.push(finallyExpr2); + + // Dispatch based on pendingAction + // if (pendingAction == 1) return pendingValue; + if (returnType != Type.void && pendingValueLocal) { + dispatchStmts.push( + module.if( + module.binary(BinaryOp.EqI32, + module.local_get(pendingActionLocal.index, TypeRef.I32), + module.i32(1) + ), + module.return(module.local_get(pendingValueLocal.index, returnType.toRef())) + ) + ); + } else { + dispatchStmts.push( + module.if( + module.binary(BinaryOp.EqI32, + module.local_get(pendingActionLocal.index, TypeRef.I32), + module.i32(1) + ), + module.return() + ) + ); + } + + // The full structure: + // (block $dispatch ;; Branch here skips try but runs finally + // (try $try_finally + // (do ...) + // (catch_all ... rethrow) + // ) + // ) + // finally code ;; Runs after try completes or after br $dispatch + // dispatch logic ;; if pendingAction==1 return pendingValue + + // Wrap the try in a block that return can branch to + let tryBlock = module.block(dispatchLabel, [outerTryExpr]); + + // For functions that return a value, add unreachable at the end + // This handles the case where normal completion didn't have a return + // (in theory this path shouldn't be reachable if all paths return) + if (returnType != Type.void) { + dispatchStmts.push(module.unreachable()); + } + + let fullBlock = module.block(null, [ + tryBlock, + ...dispatchStmts + ]); + // Merge flow states if (catchFlow) { if (tryFlowTerminates && catchFlowTerminates) { @@ -3282,20 +3435,10 @@ export class Compiler extends DiagnosticEmitter { outerFlow.inheritAlternatives(tryFlow, catchFlow); } } else { - // Only finally, no catch - exceptions propagate after finally outerFlow.mergeSideEffects(tryFlow); } - // For normal completion: run the outer try, then finally - // We need to compile finally again for the normal path since finallyExpr was already used - finallyFlow = outerFlow.fork(); - this.currentFlow = finallyFlow; - let finallyStmts2 = new Array(); - this.compileStatements(finallyStatements, finallyStmts2); - let finallyExpr2 = module.flatten(finallyStmts2); - this.currentFlow = outerFlow; - - return module.block(null, [outerTryExpr, finallyExpr2]); + return fullBlock; } // No finally clause diff --git a/src/flow.ts b/src/flow.ts index 9f9cd35396..9d8e7588a5 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -265,12 +265,35 @@ export class Flow { trueFlows: Map | null = null; /** Alternative flows if a compound expression is false-ish. */ falseFlows: Map | null = null; + /** Try-finally context: local index for pending action (0=none, 1=return, 2=break, 3=continue). */ + tryFinallyPendingActionLocal: i32 = -1; + /** Try-finally context: local index for pending return value. */ + tryFinallyPendingValueLocal: i32 = -1; + /** Try-finally context: label to branch to for finally dispatch. */ + tryFinallyDispatchLabel: string | null = null; + /** Try-finally context: return type for the pending value. */ + tryFinallyReturnType: Type | null = null; /** Tests if this is an inline flow. */ get isInline(): bool { return this.inlineFunction != null; } + /** Tests if this flow or any parent is in a try-finally context. */ + get isInTryFinally(): bool { + return this.tryFinallyPendingActionLocal >= 0; + } + + /** Gets the try-finally context from this flow or a parent flow. */ + getTryFinallyContext(): Flow | null { + let flow: Flow | null = this; + while (flow) { + if (flow.tryFinallyPendingActionLocal >= 0) return flow; + flow = flow.parent; + } + return null; + } + /** Gets the source function being compiled. Differs from target when inlining. */ get sourceFunction(): Function { // Obtaining the source function is useful when resolving elements relative diff --git a/tests/compiler/exceptions.debug.wat b/tests/compiler/exceptions.debug.wat index 1b61b11958..53943ed906 100644 --- a/tests/compiler/exceptions.debug.wat +++ b/tests/compiler/exceptions.debug.wat @@ -1,14 +1,15 @@ (module - (type $0 (func (param i32 i32))) - (type $1 (func (param i32) (result i32))) - (type $2 (func (param i32))) - (type $3 (func)) - (type $4 (func (result i32))) - (type $5 (func (param i32 i32) (result i32))) + (type $0 (func (param i32) (result i32))) + (type $1 (func (param i32 i32))) + (type $2 (func (result i32))) + (type $3 (func (param i32))) + (type $4 (func (param i32 i32) (result i32))) + (type $5 (func)) (type $6 (func (param i32 i32 i32))) - (type $7 (func (param i32 i32 i32 i32))) - (type $8 (func (param i32 i32 i64) (result i32))) - (type $9 (func (param i32 i32 i32 i32 i32) (result i32))) + (type $7 (func (param i32 i32 i32) (result i32))) + (type $8 (func (param i32 i32 i32 i32))) + (type $9 (func (param i32 i32 i64) (result i32))) + (type $10 (func (param i32 i32 i32 i32 i32) (result i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (global $~lib/rt/itcms/total (mut i32) (i32.const 0)) (global $~lib/rt/itcms/threshold (mut i32) (i32.const 0)) @@ -26,14 +27,25 @@ (global $~lib/native/ASC_LOW_MEMORY_LIMIT i32 (i32.const 0)) (global $~lib/native/ASC_SHRINK_LEVEL i32 (i32.const 0)) (global $exceptions/finallyRan (mut i32) (i32.const 0)) + (global $exceptions/returnInCatchFinallyRan (mut i32) (i32.const 0)) (global $exceptions/tryCatchFinallyRan (mut i32) (i32.const 0)) (global $exceptions/tryCatchFinallyResult (mut i32) (i32.const 0)) (global $exceptions/finallyWithExceptionRan (mut i32) (i32.const 0)) (global $exceptions/finallyNormalRan (mut i32) (i32.const 0)) - (global $~lib/rt/__rtti_base i32 (i32.const 688)) - (global $~lib/memory/__data_end i32 (i32.const 712)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 33480)) - (global $~lib/memory/__heap_base i32 (i32.const 33480)) + (global $exceptions/Resource.instances (mut i32) (i32.const 0)) + (global $exceptions/Resource.disposed (mut i32) (i32.const 0)) + (global $exceptions/calc (mut i32) (i32.const 0)) + (global $exceptions/outer (mut i32) (i32.const 0)) + (global $~lib/native/ASC_RUNTIME i32 (i32.const 2)) + (global $exceptions/rethrowFinallyRan (mut i32) (i32.const 0)) + (global $exceptions/sm (mut i32) (i32.const 0)) + (global $exceptions/deepNestingOrder (mut i32) (i32.const 416)) + (global $exceptions/counter (mut i32) (i32.const 0)) + (global $exceptions/multiReturnFinallyCount (mut i32) (i32.const 0)) + (global $~lib/rt/__rtti_base i32 (i32.const 1744)) + (global $~lib/memory/__data_end i32 (i32.const 1804)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34572)) + (global $~lib/memory/__heap_base i32 (i32.const 34572)) (memory $0 1) (data $0 (i32.const 12) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e\00\00\00\00\00") (data $1 (i32.const 80) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") @@ -51,10 +63,35 @@ (data $13 (i32.const 572) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00o\00u\00t\00e\00r\00\00\00") (data $14 (i32.const 604) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\n\00\00\00e\00r\00r\00o\00r\00\00\00") (data $15 (i32.const 636) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1c\00\00\00w\00i\00l\00l\00 \00p\00r\00o\00p\00a\00g\00a\00t\00e\00") - (data $16 (i32.const 688) "\05\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00") + (data $16 (i32.const 684) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\0c\00\00\00c\00u\00s\00t\00o\00m\00") + (data $17 (i32.const 716) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\16\00\00\00w\00o\00r\00k\00 \00f\00a\00i\00l\00e\00d\00\00\00\00\00\00\00") + (data $18 (i32.const 764) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00 \00\00\00d\00i\00v\00i\00s\00i\00o\00n\00 \00b\00y\00 \00z\00e\00r\00o\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $19 (i32.const 828) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\16\00\00\00i\00n\00n\00e\00r\00 \00e\00r\00r\00o\00r\00\00\00\00\00\00\00") + (data $20 (i32.const 876) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1a\00\00\00w\00r\00a\00p\00p\00e\00d\00 \00e\00r\00r\00o\00r\00\00\00") + (data $21 (i32.const 924) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\14\00\00\00R\00a\00n\00g\00e\00E\00r\00r\00o\00r\00\00\00\00\00\00\00\00\00") + (data $22 (i32.const 972) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1c\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00l\00e\00n\00g\00t\00h\00") + (data $23 (i32.const 1020) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\18\00\00\00s\00u\00m\00 \00e\00x\00c\00e\00e\00d\00e\00d\00\00\00\00\00") + (data $24 (i32.const 1068) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\10\00\00\00o\00r\00i\00g\00i\00n\00a\00l\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $25 (i32.const 1116) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\14\00\00\00r\00e\00t\00h\00r\00o\00w\00n\00:\00 \00\00\00\00\00\00\00\00\00") + (data $26 (i32.const 1164) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\1a\00\00\00i\00n\00v\00a\00l\00i\00d\00 \00s\00t\00a\00t\00e\00\00\00") + (data $27 (i32.const 1212) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00t\001\00,\00\00\00\00\00\00\00") + (data $28 (i32.const 1244) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00t\002\00,\00\00\00\00\00\00\00") + (data $29 (i32.const 1276) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00t\003\00,\00\00\00\00\00\00\00") + (data $30 (i32.const 1308) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\08\00\00\00d\00e\00e\00p\00\00\00\00\00") + (data $31 (i32.const 1340) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00c\003\00,\00\00\00\00\00\00\00") + (data $32 (i32.const 1372) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\0e\00\00\00r\00e\00t\00h\00r\00o\00w\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $33 (i32.const 1420) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00f\003\00,\00\00\00\00\00\00\00") + (data $34 (i32.const 1452) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00c\002\00,\00\00\00\00\00\00\00") + (data $35 (i32.const 1484) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00f\002\00,\00\00\00\00\00\00\00") + (data $36 (i32.const 1516) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00c\001\00,\00\00\00\00\00\00\00") + (data $37 (i32.const 1548) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\06\00\00\00f\001\00,\00\00\00\00\00\00\00") + (data $38 (i32.const 1580) "L\00\00\00\00\00\00\00\00\00\00\00\02\00\00\000\00\00\00t\001\00,\00t\002\00,\00t\003\00,\00c\003\00,\00f\003\00,\00c\002\00,\00f\002\00,\00f\001\00,\00\00\00\00\00\00\00\00\00\00\00\00\00") + (data $39 (i32.const 1660) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\16\00\00\00m\00a\00x\00 \00r\00e\00a\00c\00h\00e\00d\00\00\00\00\00\00\00") + (data $40 (i32.const 1708) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\08\00\00\00z\00e\00r\00o\00\00\00\00\00") + (data $41 (i32.const 1744) "\0e\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 \00\00\00") (table $0 1 1 funcref) (elem $0 (i32.const 1)) - (tag $$error (type $2) (param i32)) + (tag $$error (type $3) (param i32)) (export "memory" (memory $0)) (start $~start) (func $~lib/rt/itcms/Object#set:nextWithColor (param $this i32) (param $nextWithColor i32) @@ -2496,6 +2533,7 @@ unreachable ) (func $exceptions/testFinally + (local $0 i32) try $try_finally|0 catch_all i32.const 1 @@ -2504,6 +2542,12 @@ end i32.const 1 global.set $exceptions/finallyRan + local.get $0 + i32.const 1 + i32.eq + if + return + end ) (func $exceptions/testNested (result i32) (local $e i32) @@ -2531,17 +2575,59 @@ end unreachable ) + (func $exceptions/testReturnInCatchFinally (result i32) + (local $e i32) + (local $1 i32) + (local $2 i32) + (local $e|3 i32) + block $finally_dispatch|0 + try $try_finally|0 + try $try|1 + i32.const 0 + i32.const 624 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e|3 + i32.const 10 + local.set $2 + i32.const 1 + local.set $1 + br $finally_dispatch|0 + end + unreachable + catch_all + i32.const 1 + global.set $exceptions/returnInCatchFinallyRan + rethrow $try_finally|0 + end + unreachable + end + i32.const 1 + global.set $exceptions/returnInCatchFinallyRan + local.get $1 + i32.const 1 + i32.eq + if + local.get $2 + return + end + unreachable + ) (func $exceptions/testTryCatchFinally (local $e i32) + (local $1 i32) + (local $e|2 i32) try $try_finally|0 - try $try|0 + try $try|1 i32.const 0 i32.const 624 call $~lib/error/Error#constructor throw $$error catch $$error - local.set $e + local.set $e|2 i32.const 10 global.set $exceptions/tryCatchFinallyResult end @@ -2552,8 +2638,15 @@ end i32.const 1 global.set $exceptions/tryCatchFinallyRan + local.get $1 + i32.const 1 + i32.eq + if + return + end ) (func $exceptions/innerThrow + (local $0 i32) try $try_finally|0 i32.const 0 i32.const 656 @@ -2585,6 +2678,8 @@ return ) (func $exceptions/testFinallyNormalCompletion (result i32) + (local $0 i32) + (local $1 i32) try $try_finally|0 catch_all i32.const 1 @@ -2593,430 +2688,3207 @@ end i32.const 1 global.set $exceptions/finallyNormalRan - global.get $exceptions/finallyNormalRan - if (result i32) - i32.const 1 - else - i32.const 0 - end - return - ) - (func $~lib/rt/__visit_globals (param $0 i32) - (local $1 i32) - i32.const 224 - local.get $0 - call $~lib/rt/itcms/__visit - i32.const 32 - local.get $0 - call $~lib/rt/itcms/__visit - ) - (func $~lib/arraybuffer/ArrayBufferView~visit (param $0 i32) (param $1 i32) - (local $2 i32) - local.get $0 - local.get $1 - call $~lib/object/Object~visit - local.get $0 - i32.load - local.get $1 - call $~lib/rt/itcms/__visit - ) - (func $~lib/object/Object~visit (param $0 i32) (param $1 i32) - ) - (func $~lib/error/Error~visit (param $0 i32) (param $1 i32) - (local $2 i32) - local.get $0 - local.get $1 - call $~lib/object/Object~visit - local.get $0 - i32.load - local.get $1 - call $~lib/rt/itcms/__visit - local.get $0 - i32.load offset=4 - local.get $1 - call $~lib/rt/itcms/__visit local.get $0 - i32.load offset=8 - local.get $1 - call $~lib/rt/itcms/__visit - ) - (func $~lib/rt/__visit_members (param $0 i32) (param $1 i32) - block $invalid - block $~lib/error/Error - block $~lib/arraybuffer/ArrayBufferView - block $~lib/string/String - block $~lib/arraybuffer/ArrayBuffer - block $~lib/object/Object - local.get $0 - i32.const 8 - i32.sub - i32.load - br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/error/Error $invalid - end - return - end - return - end - return - end - local.get $0 - local.get $1 - call $~lib/arraybuffer/ArrayBufferView~visit - return - end - local.get $0 + i32.const 1 + i32.eq + if local.get $1 - call $~lib/error/Error~visit return end unreachable ) - (func $~start - call $start:exceptions + (func $exceptions/CustomError#set:code (param $this i32) (param $code i32) + local.get $this + local.get $code + i32.store offset=12 ) - (func $~stack_check - global.get $~lib/memory/__stack_pointer - global.get $~lib/memory/__data_end - i32.lt_s - if - i32.const 33504 - i32.const 33552 - i32.const 1 + (func $exceptions/testCustomError (result i32) + (local $e i32) + try $try|0 + i32.const 0 + i32.const 704 + i32.const 42 + call $exceptions/CustomError#constructor + throw $$error + catch $$error + + local.set $e i32.const 1 - call $~lib/builtins/abort - unreachable + return end + unreachable ) - (func $~lib/error/Error#constructor (param $this i32) (param $message i32) (result i32) - (local $2 i32) - global.get $~lib/memory/__stack_pointer - i32.const 12 - i32.sub - global.set $~lib/memory/__stack_pointer - call $~stack_check - global.get $~lib/memory/__stack_pointer - i64.const 0 - i64.store - global.get $~lib/memory/__stack_pointer + (func $exceptions/Resource#set:id (param $this i32) (param $id i32) + local.get $this + local.get $id + i32.store + ) + (func $exceptions/Resource#doWork (param $this i32) + ) + (func $exceptions/Resource#dispose (param $this i32) + global.get $exceptions/Resource.disposed + i32.const 1 + i32.add + global.set $exceptions/Resource.disposed + ) + (func $exceptions/Resource#doWorkThatThrows (param $this i32) i32.const 0 - i32.store offset=8 + i32.const 736 + call $~lib/error/Error#constructor + throw $$error + ) + (func $exceptions/Calculator#set:value (param $this i32) (param $value i32) local.get $this - i32.eqz - if - global.get $~lib/memory/__stack_pointer - i32.const 12 - i32.const 4 - call $~lib/rt/itcms/__new - local.tee $this - i32.store - end + local.get $value + i32.store + ) + (func $exceptions/Calculator#get:value (param $this i32) (result i32) local.get $this - local.set $2 - global.get $~lib/memory/__stack_pointer - local.get $2 - i32.store offset=4 - local.get $2 - local.get $message - local.set $2 - global.get $~lib/memory/__stack_pointer - local.get $2 - i32.store offset=8 - local.get $2 - call $~lib/error/Error#set:message + i32.load + ) + (func $exceptions/Outer#set:inner (param $this i32) (param $inner i32) local.get $this - local.set $2 - global.get $~lib/memory/__stack_pointer - local.get $2 - i32.store offset=4 - local.get $2 - i32.const 384 - call $~lib/error/Error#set:name + local.get $inner + i32.store local.get $this - local.set $2 - global.get $~lib/memory/__stack_pointer - local.get $2 - i32.store offset=4 - local.get $2 - i32.const 416 - call $~lib/error/Error#set:stack + local.get $inner + i32.const 0 + call $~lib/rt/itcms/__link + ) + (func $exceptions/Outer#get:inner (param $this i32) (result i32) local.get $this - local.set $2 - global.get $~lib/memory/__stack_pointer - i32.const 12 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $2 + i32.load ) - (func $exceptions/testCatchVar (result i32) + (func $exceptions/Inner#riskyOperation (param $this i32) (result i32) (local $e i32) - (local $1 i32) - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.sub - global.set $~lib/memory/__stack_pointer - call $~stack_check - global.get $~lib/memory/__stack_pointer - i32.const 0 - i32.store try $try|0 i32.const 0 - i32.const 528 + i32.const 848 call $~lib/error/Error#constructor throw $$error catch $$error local.set $e - local.get $e - local.set $1 - global.get $~lib/memory/__stack_pointer - local.get $1 - i32.store - local.get $1 - call $~lib/error/Error#get:message - local.set $1 - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $1 - return + i32.const 0 + i32.const 896 + call $~lib/error/Error#constructor + throw $$error end unreachable ) - (func $~lib/string/String.__eq (param $left i32) (param $right i32) (result i32) - (local $leftLength i32) - (local $3 i32) - global.get $~lib/memory/__stack_pointer - i32.const 8 - i32.sub - global.set $~lib/memory/__stack_pointer - call $~stack_check - global.get $~lib/memory/__stack_pointer - i64.const 0 - i64.store - local.get $left - local.get $right - i32.eq - if - i32.const 1 - local.set $3 - global.get $~lib/memory/__stack_pointer - i32.const 8 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $3 - return - end - local.get $left + (func $~lib/array/Array#set:buffer (param $this i32) (param $buffer i32) + local.get $this + local.get $buffer + i32.store + local.get $this + local.get $buffer i32.const 0 - i32.eq - if (result i32) - i32.const 1 - else - local.get $right - i32.const 0 - i32.eq + call $~lib/rt/itcms/__link + ) + (func $~lib/array/Array#set:dataStart (param $this i32) (param $dataStart i32) + local.get $this + local.get $dataStart + i32.store offset=4 + ) + (func $~lib/array/Array#set:byteLength (param $this i32) (param $byteLength i32) + local.get $this + local.get $byteLength + i32.store offset=8 + ) + (func $~lib/array/Array#set:length_ (param $this i32) (param $length_ i32) + local.get $this + local.get $length_ + i32.store offset=12 + ) + (func $~lib/array/Array#get:length_ (param $this i32) (result i32) + local.get $this + i32.load offset=12 + ) + (func $~lib/arraybuffer/ArrayBufferView#get:byteLength (param $this i32) (result i32) + local.get $this + i32.load offset=8 + ) + (func $~lib/arraybuffer/ArrayBufferView#get:buffer (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $~lib/rt/itcms/Object#get:rtSize (param $this i32) (result i32) + local.get $this + i32.load offset=16 + ) + (func $~lib/rt/itcms/__renew (param $oldPtr i32) (param $size i32) (result i32) + (local $oldObj i32) + (local $newPtr i32) + (local $4 i32) + (local $5 i32) + local.get $oldPtr + i32.const 20 + i32.sub + local.set $oldObj + local.get $size + local.get $oldObj + call $~lib/rt/common/BLOCK#get:mmInfo + i32.const 3 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.sub + i32.le_u + if + local.get $oldObj + local.get $size + call $~lib/rt/itcms/Object#set:rtSize + local.get $oldPtr + return + end + local.get $size + local.get $oldObj + call $~lib/rt/itcms/Object#get:rtId + call $~lib/rt/itcms/__new + local.set $newPtr + local.get $newPtr + local.get $oldPtr + local.get $size + local.tee $4 + local.get $oldObj + call $~lib/rt/itcms/Object#get:rtSize + local.tee $5 + local.get $4 + local.get $5 + i32.lt_u + select + memory.copy + local.get $newPtr + return + ) + (func $~lib/array/Array#get:dataStart (param $this i32) (result i32) + local.get $this + i32.load offset=4 + ) + (func $exceptions/testRethrowWithFinally (result i32) + (local $e i32) + i32.const 0 + global.set $exceptions/rethrowFinallyRan + try $try|0 + call $exceptions/innerRethrow + catch $$error + + local.set $e + global.get $exceptions/rethrowFinallyRan + if (result i32) + i32.const 1 + else + i32.const 0 + end + return end + i32.const 0 + return + ) + (func $exceptions/StateMachine#set:state (param $this i32) (param $state i32) + local.get $this + local.get $state + i32.store + ) + (func $exceptions/StateMachine#set:errorState (param $this i32) (param $errorState i32) + local.get $this + local.get $errorState + i32.store8 offset=4 + ) + (func $exceptions/StateMachine#get:state (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $exceptions/StateMachine#get:errorState (param $this i32) (result i32) + local.get $this + i32.load8_u offset=4 + ) + (func $exceptions/Counter#set:count (param $this i32) (param $count i32) + local.get $this + local.get $count + i32.store + ) + (func $exceptions/Counter#get:count (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $exceptions/testReturnFromTry (result i32) + (local $e i32) + (local $1 i32) + (local $2 i32) + (local $e|3 i32) + block $finally_dispatch|0 + try $try_finally|0 + try $try|1 + i32.const 42 + local.set $2 + i32.const 1 + local.set $1 + br $finally_dispatch|0 + catch $$error + + local.set $e|3 + i32.const -1 + local.set $2 + i32.const 1 + local.set $1 + br $finally_dispatch|0 + end + unreachable + catch_all + rethrow $try_finally|0 + end + unreachable + end + local.get $1 + i32.const 1 + i32.eq + if + local.get $2 + return + end + unreachable + ) + (func $exceptions/testMultipleReturnsWithFinally (param $x i32) (result i32) + (local $e i32) + (local $2 i32) + (local $3 i32) + (local $e|4 i32) + block $finally_dispatch|0 + try $try_finally|0 + try $try|1 + local.get $x + i32.const 0 + i32.lt_s + if + i32.const -1 + local.set $3 + i32.const 1 + local.set $2 + br $finally_dispatch|0 + end + local.get $x + i32.const 0 + i32.eq + if + i32.const 0 + i32.const 1728 + call $~lib/error/Error#constructor + throw $$error + end + local.get $x + i32.const 100 + i32.gt_s + if + i32.const 100 + local.set $3 + i32.const 1 + local.set $2 + br $finally_dispatch|0 + end + local.get $x + local.set $3 + i32.const 1 + local.set $2 + br $finally_dispatch|0 + catch $$error + + local.set $e|4 + i32.const 0 + local.set $3 + i32.const 1 + local.set $2 + br $finally_dispatch|0 + end + unreachable + catch_all + global.get $exceptions/multiReturnFinallyCount + i32.const 1 + i32.add + global.set $exceptions/multiReturnFinallyCount + rethrow $try_finally|0 + end + unreachable + end + global.get $exceptions/multiReturnFinallyCount + i32.const 1 + i32.add + global.set $exceptions/multiReturnFinallyCount + local.get $2 + i32.const 1 + i32.eq if - i32.const 0 - local.set $3 - global.get $~lib/memory/__stack_pointer - i32.const 8 - i32.add - global.set $~lib/memory/__stack_pointer local.get $3 return end - local.get $left - local.set $3 + unreachable + ) + (func $~lib/rt/__visit_globals (param $0 i32) + (local $1 i32) + global.get $exceptions/calc + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $exceptions/outer + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $exceptions/sm + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $exceptions/deepNestingOrder + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $exceptions/counter + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + i32.const 224 + local.get $0 + call $~lib/rt/itcms/__visit + i32.const 992 + local.get $0 + call $~lib/rt/itcms/__visit + i32.const 32 + local.get $0 + call $~lib/rt/itcms/__visit + ) + (func $~lib/arraybuffer/ArrayBufferView~visit (param $0 i32) (param $1 i32) + (local $2 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + i32.load + local.get $1 + call $~lib/rt/itcms/__visit + ) + (func $~lib/object/Object~visit (param $0 i32) (param $1 i32) + ) + (func $~lib/error/Error~visit (param $0 i32) (param $1 i32) + (local $2 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + i32.load + local.get $1 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=4 + local.get $1 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=8 + local.get $1 + call $~lib/rt/itcms/__visit + ) + (func $exceptions/CustomError~visit (param $0 i32) (param $1 i32) + local.get $0 + local.get $1 + call $~lib/error/Error~visit + ) + (func $exceptions/Outer~visit (param $0 i32) (param $1 i32) + (local $2 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + i32.load + local.get $1 + call $~lib/rt/itcms/__visit + ) + (func $~lib/array/Array#get:buffer (param $this i32) (result i32) + local.get $this + i32.load + ) + (func $~lib/array/Array~visit (param $0 i32) (param $1 i32) + local.get $0 + local.get $1 + call $~lib/object/Object~visit + local.get $0 + local.get $1 + call $~lib/array/Array#__visit + ) + (func $~lib/error/RangeError~visit (param $0 i32) (param $1 i32) + local.get $0 + local.get $1 + call $~lib/error/Error~visit + ) + (func $~lib/rt/__visit_members (param $0 i32) (param $1 i32) + block $invalid + block $exceptions/Counter + block $exceptions/StateMachine + block $~lib/error/RangeError + block $~lib/array/Array + block $exceptions/Inner + block $exceptions/Outer + block $exceptions/Calculator + block $exceptions/Resource + block $exceptions/CustomError + block $~lib/error/Error + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + block $~lib/object/Object + local.get $0 + i32.const 8 + i32.sub + i32.load + br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/error/Error $exceptions/CustomError $exceptions/Resource $exceptions/Calculator $exceptions/Outer $exceptions/Inner $~lib/array/Array $~lib/error/RangeError $exceptions/StateMachine $exceptions/Counter $invalid + end + return + end + return + end + return + end + local.get $0 + local.get $1 + call $~lib/arraybuffer/ArrayBufferView~visit + return + end + local.get $0 + local.get $1 + call $~lib/error/Error~visit + return + end + local.get $0 + local.get $1 + call $exceptions/CustomError~visit + return + end + return + end + return + end + local.get $0 + local.get $1 + call $exceptions/Outer~visit + return + end + return + end + local.get $0 + local.get $1 + call $~lib/array/Array~visit + return + end + local.get $0 + local.get $1 + call $~lib/error/RangeError~visit + return + end + return + end + return + end + unreachable + ) + (func $~start + call $start:exceptions + ) + (func $~stack_check + global.get $~lib/memory/__stack_pointer + global.get $~lib/memory/__data_end + i32.lt_s + if + i32.const 34592 + i32.const 34640 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~lib/error/Error#constructor (param $this i32) (param $message i32) (result i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.const 4 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + local.get $message + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=8 + local.get $2 + call $~lib/error/Error#set:message + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + i32.const 384 + call $~lib/error/Error#set:name + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + i32.const 416 + call $~lib/error/Error#set:stack + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + ) + (func $exceptions/testCatchVar (result i32) + (local $e i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + try $try|0 + i32.const 0 + i32.const 528 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e + local.get $e + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store + local.get $1 + call $~lib/error/Error#get:message + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + return + end + unreachable + ) + (func $~lib/string/String.__eq (param $left i32) (param $right i32) (result i32) + (local $leftLength i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $left + local.get $right + i32.eq + if + i32.const 1 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + i32.const 0 + i32.eq + if (result i32) + i32.const 1 + else + local.get $right + i32.const 0 + i32.eq + end + if + i32.const 0 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/string/String#get:length + local.set $leftLength + local.get $leftLength + local.get $right + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/string/String#get:length + i32.ne + if + i32.const 0 + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + end + local.get $left + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + i32.const 0 + local.get $right + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=4 + local.get $3 + i32.const 0 + local.get $leftLength + call $~lib/util/string/compareImpl + i32.eqz + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + ) + (func $exceptions/CustomError#constructor (param $this i32) (param $message i32) (param $code i32) (result i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 16 + i32.const 5 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=4 + local.get $3 + local.get $code + call $exceptions/CustomError#set:code + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=4 + local.get $3 + local.get $message + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=8 + local.get $3 + call $~lib/error/Error#constructor + local.tee $this + i32.store + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + ) + (func $exceptions/Resource#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.const 6 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/Resource#set:id + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + global.get $exceptions/Resource.instances + i32.const 1 + i32.add + global.set $exceptions/Resource.instances + global.get $exceptions/Resource.instances + call $exceptions/Resource#set:id + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/testResourceCleanup (result i32) + (local $r i32) + (local $result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + call $exceptions/Resource#constructor + local.tee $r + i32.store + i32.const 0 + local.set $result + try $try_finally|0 + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#doWork + i32.const 1 + local.set $result + catch_all + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#dispose + rethrow $try_finally|0 + end + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#dispose + local.get $2 + i32.const 1 + i32.eq + if + local.get $3 + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + end + unreachable + ) + (func $exceptions/testResourceCleanupWithException (result i32) + (local $r i32) + (local $1 i32) + (local $2 i32) + (local $e i32) + (local $4 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + i32.const 0 + global.set $exceptions/Resource.disposed + global.get $~lib/memory/__stack_pointer + i32.const 0 + call $exceptions/Resource#constructor + local.tee $r + i32.store + try $try|0 + try $try_finally|1 + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#doWorkThatThrows + catch_all + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#dispose + rethrow $try_finally|1 + end + local.get $r + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $exceptions/Resource#dispose + local.get $1 + i32.const 1 + i32.eq + if + local.get $2 + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + end + unreachable + catch $$error + + local.set $e + global.get $exceptions/Resource.disposed + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + end + unreachable + ) + (func $exceptions/Calculator#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.const 7 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + call $~lib/object/Object#constructor + local.tee $this + i32.store + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/Calculator#set:value + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/Calculator#divide (param $this i32) (param $a i32) (param $b i32) (result i32) + (local $e i32) + (local $4 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + try $try|0 + local.get $b + i32.const 0 + i32.eq + if + i32.const 0 + i32.const 784 + call $~lib/error/Error#constructor + throw $$error + end + local.get $a + local.get $b + i32.div_s + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + catch $$error + + local.set $e + local.get $this + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store + local.get $4 + i32.const -1 + call $exceptions/Calculator#set:value + i32.const 0 + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + end + unreachable + ) + (func $exceptions/Calculator#safeDivide (param $this i32) (param $a i32) (param $b i32) (result i32) + (local $e i32) + (local $4 i32) + (local $5 i32) + (local $e|6 i32) + (local $7 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + block $finally_dispatch|0 + try $try_finally|0 + try $try|1 + local.get $b + i32.const 0 + i32.eq + if + i32.const 0 + i32.const 784 + call $~lib/error/Error#constructor + throw $$error + end + local.get $this + local.set $7 + global.get $~lib/memory/__stack_pointer + local.get $7 + i32.store + local.get $7 + local.get $a + local.get $b + i32.div_s + call $exceptions/Calculator#set:value + local.get $this + local.set $7 + global.get $~lib/memory/__stack_pointer + local.get $7 + i32.store + local.get $7 + call $exceptions/Calculator#get:value + local.set $5 + i32.const 1 + local.set $4 + br $finally_dispatch|0 + catch $$error + + local.set $e|6 + i32.const -1 + local.set $5 + i32.const 1 + local.set $4 + br $finally_dispatch|0 + end + unreachable + catch_all + rethrow $try_finally|0 + end + unreachable + end + local.get $4 + i32.const 1 + i32.eq + if + local.get $5 + local.set $7 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $7 + return + end + unreachable + ) + (func $exceptions/Inner#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 9 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + call $~lib/object/Object#constructor + local.tee $this + i32.store + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/Outer#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.const 8 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/Outer#set:inner + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/Inner#constructor + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=8 + local.get $1 + call $exceptions/Outer#set:inner + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/Outer#process (param $this i32) (result i32) + (local $e i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + try $try|0 + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + call $exceptions/Outer#get:inner + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + call $exceptions/Inner#riskyOperation + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + return + catch $$error + + local.set $e + i32.const -1 + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + return + end + unreachable + ) + (func $~lib/error/RangeError#constructor (param $this i32) (param $message i32) (result i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.const 11 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + local.get $message + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=8 + local.get $2 + call $~lib/error/Error#constructor + local.tee $this + i32.store + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + i32.const 944 + call $~lib/error/Error#set:name + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + ) + (func $~lib/array/Array#constructor (param $this i32) (param $length i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $bufferSize i32) + (local $buffer i32) + (local $6 i32) + global.get $~lib/memory/__stack_pointer + i32.const 16 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store offset=8 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 16 + i32.const 10 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + i32.const 0 + call $~lib/array/Array#set:buffer + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + i32.const 0 + call $~lib/array/Array#set:dataStart + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + i32.const 0 + call $~lib/array/Array#set:byteLength + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + i32.const 0 + call $~lib/array/Array#set:length_ + local.get $length + i32.const 1073741820 + i32.const 2 + i32.shr_u + i32.gt_u + if + i32.const 0 + i32.const 992 + call $~lib/error/RangeError#constructor + throw $$error + end + local.get $length + local.tee $2 + i32.const 8 + local.tee $3 + local.get $2 + local.get $3 + i32.gt_u + select + i32.const 2 + i32.shl + local.set $bufferSize + global.get $~lib/memory/__stack_pointer + local.get $bufferSize + i32.const 1 + call $~lib/rt/itcms/__new + local.tee $buffer + i32.store offset=8 + i32.const 2 + global.get $~lib/shared/runtime/Runtime.Incremental + i32.ne + drop + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + local.get $buffer + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=12 + local.get $6 + call $~lib/array/Array#set:buffer + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + local.get $buffer + call $~lib/array/Array#set:dataStart + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + local.get $bufferSize + call $~lib/array/Array#set:byteLength + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store offset=4 + local.get $6 + local.get $length + call $~lib/array/Array#set:length_ + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + i32.const 16 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $6 + ) + (func $~lib/array/ensureCapacity (param $array i32) (param $newSize i32) (param $alignLog2 i32) (param $canGrow i32) + (local $oldCapacity i32) + (local $oldData i32) + (local $6 i32) + (local $7 i32) + (local $newCapacity i32) + (local $9 i32) + (local $10 i32) + (local $11 i32) + (local $12 i32) + (local $newData i32) + (local $14 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + local.get $array + local.set $14 + global.get $~lib/memory/__stack_pointer + local.get $14 + i32.store + local.get $14 + call $~lib/arraybuffer/ArrayBufferView#get:byteLength + local.set $oldCapacity + local.get $newSize + local.get $oldCapacity + local.get $alignLog2 + i32.shr_u + i32.gt_u + if + local.get $newSize + i32.const 1073741820 + local.get $alignLog2 + i32.shr_u + i32.gt_u + if + i32.const 0 + i32.const 992 + call $~lib/error/RangeError#constructor + throw $$error + end + local.get $array + local.set $14 + global.get $~lib/memory/__stack_pointer + local.get $14 + i32.store + local.get $14 + call $~lib/arraybuffer/ArrayBufferView#get:buffer + local.set $oldData + local.get $newSize + local.tee $6 + i32.const 8 + local.tee $7 + local.get $6 + local.get $7 + i32.gt_u + select + local.get $alignLog2 + i32.shl + local.set $newCapacity + local.get $canGrow + if + local.get $oldCapacity + i32.const 1 + i32.shl + local.tee $9 + i32.const 1073741820 + local.tee $10 + local.get $9 + local.get $10 + i32.lt_u + select + local.tee $11 + local.get $newCapacity + local.tee $12 + local.get $11 + local.get $12 + i32.gt_u + select + local.set $newCapacity + end + local.get $oldData + local.get $newCapacity + call $~lib/rt/itcms/__renew + local.set $newData + i32.const 2 + global.get $~lib/shared/runtime/Runtime.Incremental + i32.ne + drop + local.get $newData + local.get $oldData + i32.ne + if + local.get $array + local.get $newData + i32.store + local.get $array + local.get $newData + i32.store offset=4 + local.get $array + local.get $newData + i32.const 0 + call $~lib/rt/itcms/__link + end + local.get $array + local.get $newCapacity + i32.store offset=8 + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $~lib/array/Array#__set (param $this i32) (param $index i32) (param $value i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + local.get $index + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/array/Array#get:length_ + i32.ge_u + if + local.get $index + i32.const 0 + i32.lt_s + if + i32.const 0 + i32.const 224 + call $~lib/error/RangeError#constructor + throw $$error + end + local.get $this + local.get $index + i32.const 1 + i32.add + i32.const 2 + i32.const 1 + call $~lib/array/ensureCapacity + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + local.get $index + i32.const 1 + i32.add + call $~lib/array/Array#set:length_ + end + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/array/Array#get:dataStart + local.get $index + i32.const 2 + i32.shl + i32.add + local.get $value + i32.store + i32.const 0 + drop + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $~lib/array/Array#get:length (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store + local.get $1 + call $~lib/array/Array#get:length_ + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + return + ) + (func $~lib/array/Array#__get (param $this i32) (param $index i32) (result i32) + (local $value i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + local.get $index + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/array/Array#get:length_ + i32.ge_u + if + i32.const 0 + i32.const 224 + call $~lib/error/RangeError#constructor + throw $$error + end + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/array/Array#get:dataStart + local.get $index + i32.const 2 + i32.shl + i32.add + i32.load + local.set $value + i32.const 0 + drop + local.get $value + local.set $3 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $3 + return + ) + (func $exceptions/testArrayWithExceptions (result i32) + (local $arr i32) + (local $sum i32) + (local $i i32) + (local $e i32) + (local $4 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 3 + call $~lib/array/Array#constructor + local.tee $arr + i32.store + local.get $arr + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + i32.const 0 + i32.const 1 + call $~lib/array/Array#__set + local.get $arr + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + i32.const 1 + i32.const 2 + call $~lib/array/Array#__set + local.get $arr + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + i32.const 2 + i32.const 3 + call $~lib/array/Array#__set + i32.const 0 + local.set $sum + try $try|0 + i32.const 0 + local.set $i + loop $for-loop|1 + local.get $i + local.get $arr + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + call $~lib/array/Array#get:length + i32.lt_s + if + local.get $sum + local.get $arr + local.set $4 + global.get $~lib/memory/__stack_pointer + local.get $4 + i32.store offset=4 + local.get $4 + local.get $i + call $~lib/array/Array#__get + i32.add + local.set $sum + local.get $sum + i32.const 5 + i32.gt_s + if + i32.const 0 + i32.const 1040 + call $~lib/error/Error#constructor + throw $$error + end + local.get $i + i32.const 1 + i32.add + local.set $i + br $for-loop|1 + end + end + catch $$error + + local.set $e + local.get $sum + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + end + i32.const 0 + local.set $4 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $4 + return + ) + (func $~lib/string/String#concat (param $this i32) (param $other i32) (result i32) + (local $thisSize i32) + (local $otherSize i32) + (local $outSize i32) + (local $out i32) + (local $6 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store + local.get $6 + call $~lib/string/String#get:length + i32.const 1 + i32.shl + local.set $thisSize + local.get $other + local.set $6 + global.get $~lib/memory/__stack_pointer + local.get $6 + i32.store + local.get $6 + call $~lib/string/String#get:length + i32.const 1 + i32.shl + local.set $otherSize + local.get $thisSize + local.get $otherSize + i32.add + local.set $outSize + local.get $outSize + i32.const 0 + i32.eq + if + i32.const 416 + local.set $6 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $6 + return + end + global.get $~lib/memory/__stack_pointer + local.get $outSize + i32.const 2 + call $~lib/rt/itcms/__new + local.tee $out + i32.store offset=4 + local.get $out + local.get $this + local.get $thisSize + memory.copy + local.get $out + local.get $thisSize + i32.add + local.get $other + local.get $otherSize + memory.copy + local.get $out + local.set $6 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $6 + return + ) + (func $~lib/string/String.__concat (param $left i32) (param $right i32) (result i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $left + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + local.get $right + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + call $~lib/string/String#concat + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + return + ) + (func $exceptions/innerRethrow + (local $e i32) + (local $1 i32) + (local $e|2 i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + try $try_finally|0 + try $try|1 + i32.const 0 + i32.const 1088 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e|2 + i32.const 0 + global.set $exceptions/rethrowFinallyRan + i32.const 0 + i32.const 1136 + local.get $e|2 + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=8 + local.get $3 + call $~lib/error/Error#get:message + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store offset=4 + local.get $3 + call $~lib/string/String.__concat + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + call $~lib/error/Error#constructor + throw $$error + end + unreachable + catch_all + i32.const 1 + global.set $exceptions/rethrowFinallyRan + rethrow $try_finally|0 + end + unreachable + ) + (func $exceptions/StateMachine#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 5 + i32.const 12 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + call $~lib/object/Object#constructor + local.tee $this + i32.store + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/StateMachine#set:state + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/StateMachine#set:errorState + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/StateMachine#transition (param $this i32) (param $newState i32) + (local $e i32) + (local $3 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + try $try|0 + local.get $newState + i32.const 0 + i32.lt_s + if + i32.const 0 + i32.const 1184 + call $~lib/error/Error#constructor + throw $$error + end + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + local.get $newState + call $exceptions/StateMachine#set:state + catch $$error + + local.set $e + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + i32.const 1 + call $exceptions/StateMachine#set:errorState + local.get $this + local.set $3 + global.get $~lib/memory/__stack_pointer + local.get $3 + i32.store + local.get $3 + i32.const -1 + call $exceptions/StateMachine#set:state + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $exceptions/StateMachine#reset (param $this i32) + (local $1 i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + try $try_finally|0 + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + i32.const 0 + call $exceptions/StateMachine#set:state + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + i32.const 0 + call $exceptions/StateMachine#set:errorState + catch_all + rethrow $try_finally|0 + end + local.get $1 + i32.const 1 + i32.eq + if + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + return + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $exceptions/testDeepNesting (result i32) + (local $e i32) + (local $1 i32) + (local $2 i32) + (local $e|3 i32) + (local $e|4 i32) + (local $5 i32) + (local $6 i32) + (local $e|7 i32) + (local $8 i32) + (local $9 i32) + (local $e|10 i32) + (local $e|11 i32) + (local $e|12 i32) + (local $13 i32) + (local $14 i32) + (local $e|15 i32) + (local $16 i32) + (local $17 i32) + (local $e|18 i32) + (local $e|19 i32) + (local $20 i32) + (local $21 i32) + (local $e|22 i32) + (local $23 i32) + (local $24 i32) + (local $e|25 i32) + (local $e|26 i32) + (local $e|27 i32) + (local $28 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + i32.const 416 + global.set $exceptions/deepNestingOrder + try $try_finally|0 + try $try|7 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1232 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + try $try_finally|8 + try $try|11 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1264 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + try $try_finally|12 + try $try|13 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1296 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + i32.const 0 + i32.const 1328 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e|25 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1360 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + i32.const 0 + i32.const 1392 + call $~lib/error/Error#constructor + throw $$error + end + unreachable + catch_all + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1440 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + rethrow $try_finally|12 + end + unreachable + catch $$error + + local.set $e|26 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1472 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + end + catch_all + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1504 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + rethrow $try_finally|8 + end + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1504 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + local.get $20 + i32.const 1 + i32.eq + if + local.get $21 + local.set $28 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $28 + return + end + unreachable + catch $$error + + local.set $e|27 + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1536 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + end + catch_all + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1568 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + rethrow $try_finally|0 + end + global.get $exceptions/deepNestingOrder + local.set $28 + global.get $~lib/memory/__stack_pointer + local.get $28 + i32.store + local.get $28 + i32.const 1568 + call $~lib/string/String.__concat + global.set $exceptions/deepNestingOrder + local.get $13 + i32.const 1 + i32.eq + if + local.get $14 + local.set $28 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $28 + return + end + unreachable + ) + (func $exceptions/Counter#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.const 13 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + call $~lib/object/Object#constructor + local.tee $this + i32.store + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=4 + local.get $1 + i32.const 0 + call $exceptions/Counter#set:count + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $exceptions/Counter#increment (param $this i32) (result i32) + (local $e i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + try $try|0 + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store offset=4 + local.get $2 + call $exceptions/Counter#get:count + i32.const 1 + i32.add + call $exceptions/Counter#set:count + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + call $exceptions/Counter#get:count + i32.const 3 + i32.gt_s + if + i32.const 0 + i32.const 1680 + call $~lib/error/Error#constructor + throw $$error + end + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + call $exceptions/Counter#get:count + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + return + catch $$error + + local.set $e + i32.const -1 + local.set $2 + global.get $~lib/memory/__stack_pointer + i32.const 8 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $2 + return + end + unreachable + ) + (func $start:exceptions + (local $0 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + memory.size + i32.const 16 + i32.shl + global.get $~lib/memory/__heap_base + i32.sub + i32.const 1 + i32.shr_u + global.set $~lib/rt/itcms/threshold + i32.const 80 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/pinSpace + i32.const 176 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/toSpace + i32.const 272 + call $~lib/rt/itcms/initLazy + global.set $~lib/rt/itcms/fromSpace + call $exceptions/testTryCatch + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 15 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testCatchVar + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 528 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 26 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testNoThrow + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 36 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinally + global.get $exceptions/finallyRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 48 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testNested + i32.const 42 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 63 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testReturnInCatchFinally + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 76 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/returnInCatchFinallyRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 77 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testTryCatchFinally + global.get $exceptions/tryCatchFinallyResult + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 92 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/tryCatchFinallyRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 93 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinallyWithException + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 112 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testFinallyNormalCompletion + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 124 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testCustomError + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 147 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testResourceCleanup + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 185 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/Resource.disposed + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 186 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testResourceCleanupWithException + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 203 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $exceptions/Calculator#constructor + global.set $exceptions/calc + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 10 + i32.const 2 + call $exceptions/Calculator#divide + i32.const 5 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 237 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 10 + i32.const 0 + call $exceptions/Calculator#divide + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 238 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/Calculator#get:value + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 239 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 0 + call $exceptions/Calculator#set:value + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 20 + i32.const 4 + call $exceptions/Calculator#safeDivide + i32.const 5 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 242 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/calc + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 20 + i32.const 0 + call $exceptions/Calculator#safeDivide + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 243 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $exceptions/Outer#constructor + global.set $exceptions/outer + global.get $exceptions/outer + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/Outer#process + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 274 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testArrayWithExceptions + i32.const 6 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 296 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testRethrowWithFinally + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 321 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $exceptions/StateMachine#constructor + global.set $exceptions/sm + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 1 + call $exceptions/StateMachine#transition + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/StateMachine#get:state + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 352 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/StateMachine#get:errorState + i32.const 0 + i32.ne + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 353 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const -5 + call $exceptions/StateMachine#transition + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/StateMachine#get:state + i32.const -1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 356 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/sm + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/StateMachine#get:errorState + i32.const 0 + i32.ne + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 357 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/sm + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $3 + local.get $0 i32.store - local.get $3 - call $~lib/string/String#get:length - local.set $leftLength - local.get $leftLength - local.get $right - local.set $3 + local.get $0 + call $exceptions/StateMachine#reset + global.get $exceptions/sm + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $3 + local.get $0 i32.store - local.get $3 - call $~lib/string/String#get:length - i32.ne + local.get $0 + call $exceptions/StateMachine#get:state + i32.const 0 + i32.eq + i32.eqz if i32.const 0 - local.set $3 - global.get $~lib/memory/__stack_pointer - i32.const 8 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $3 - return + i32.const 480 + i32.const 360 + i32.const 1 + call $~lib/builtins/abort + unreachable end - local.get $left - local.set $3 + global.get $exceptions/sm + local.set $0 global.get $~lib/memory/__stack_pointer - local.get $3 + local.get $0 i32.store - local.get $3 + local.get $0 + call $exceptions/StateMachine#get:errorState i32.const 0 - local.get $right - local.set $3 - global.get $~lib/memory/__stack_pointer - local.get $3 - i32.store offset=4 - local.get $3 + i32.ne i32.const 0 - local.get $leftLength - call $~lib/util/string/compareImpl + i32.eq i32.eqz - local.set $3 - global.get $~lib/memory/__stack_pointer - i32.const 8 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $3 - return - ) - (func $start:exceptions - (local $0 i32) - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.sub - global.set $~lib/memory/__stack_pointer - call $~stack_check + if + i32.const 0 + i32.const 480 + i32.const 361 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testDeepNesting + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 393 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/deepNestingOrder + local.set $0 global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.const 1600 + call $~lib/string/String.__eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 394 + i32.const 1 + call $~lib/builtins/abort + unreachable + end i32.const 0 + call $exceptions/Counter#constructor + global.set $exceptions/counter + global.get $exceptions/counter + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 i32.store - memory.size - i32.const 16 - i32.shl - global.get $~lib/memory/__heap_base - i32.sub - i32.const 1 - i32.shr_u - global.set $~lib/rt/itcms/threshold - i32.const 80 - call $~lib/rt/itcms/initLazy - global.set $~lib/rt/itcms/pinSpace - i32.const 176 - call $~lib/rt/itcms/initLazy - global.set $~lib/rt/itcms/toSpace - i32.const 272 - call $~lib/rt/itcms/initLazy - global.set $~lib/rt/itcms/fromSpace - call $exceptions/testTryCatch + local.get $0 + call $exceptions/Counter#increment i32.const 1 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 15 + i32.const 414 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testCatchVar + global.get $exceptions/counter local.set $0 global.get $~lib/memory/__stack_pointer local.get $0 i32.store local.get $0 - i32.const 528 - call $~lib/string/String.__eq + call $exceptions/Counter#increment + i32.const 2 + i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 26 + i32.const 415 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testNoThrow - i32.const 1 + global.get $exceptions/counter + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/Counter#increment + i32.const 3 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 36 + i32.const 416 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testFinally - global.get $exceptions/finallyRan - i32.const 1 + global.get $exceptions/counter + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + call $exceptions/Counter#increment + i32.const -1 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 48 + i32.const 417 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testNested + call $exceptions/testReturnFromTry i32.const 42 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 63 + i32.const 429 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testTryCatchFinally - global.get $exceptions/tryCatchFinallyResult - i32.const 10 + i32.const 0 + global.set $exceptions/multiReturnFinallyCount + i32.const -5 + call $exceptions/testMultipleReturnsWithFinally + i32.const -1 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 78 + i32.const 453 i32.const 1 call $~lib/builtins/abort unreachable end - global.get $exceptions/tryCatchFinallyRan + global.get $exceptions/multiReturnFinallyCount i32.const 1 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 79 + i32.const 454 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testFinallyWithException - i32.const 1 + i32.const 0 + call $exceptions/testMultipleReturnsWithFinally + i32.const 0 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 98 + i32.const 456 i32.const 1 call $~lib/builtins/abort unreachable end - call $exceptions/testFinallyNormalCompletion - i32.const 1 + global.get $exceptions/multiReturnFinallyCount + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 457 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 50 + call $exceptions/testMultipleReturnsWithFinally + i32.const 50 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 459 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/multiReturnFinallyCount + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 460 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 200 + call $exceptions/testMultipleReturnsWithFinally + i32.const 100 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 462 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/multiReturnFinallyCount + i32.const 4 i32.eq i32.eqz if i32.const 0 i32.const 480 - i32.const 110 + i32.const 463 i32.const 1 call $~lib/builtins/abort unreachable @@ -3026,4 +5898,58 @@ i32.add global.set $~lib/memory/__stack_pointer ) + (func $~lib/array/Array#__visit (param $this i32) (param $cookie i32) + (local $2 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + i32.const 0 + drop + local.get $this + local.set $2 + global.get $~lib/memory/__stack_pointer + local.get $2 + i32.store + local.get $2 + call $~lib/array/Array#get:buffer + local.get $cookie + call $~lib/rt/itcms/__visit + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + ) + (func $~lib/object/Object#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 0 + call $~lib/rt/itcms/__new + local.tee $this + i32.store + end + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) ) diff --git a/tests/compiler/exceptions.release.wat b/tests/compiler/exceptions.release.wat index cd50a5b54d..d2fc247867 100644 --- a/tests/compiler/exceptions.release.wat +++ b/tests/compiler/exceptions.release.wat @@ -2,10 +2,10 @@ (type $0 (func (param i32))) (type $1 (func)) (type $2 (func (param i32 i32))) - (type $3 (func (result i32))) - (type $4 (func (param i32) (result i32))) - (type $5 (func (param i32 i32 i32 i32))) - (type $6 (func (param i32 i32 i64))) + (type $3 (func (param i32 i32) (result i32))) + (type $4 (func (param i32 i32 i32 i32))) + (type $5 (func (param i32 i32 i64))) + (type $6 (func (result i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (global $~lib/rt/itcms/total (mut i32) (i32.const 0)) (global $~lib/rt/itcms/threshold (mut i32) (i32.const 0)) @@ -20,7 +20,8 @@ (global $exceptions/tryCatchFinallyRan (mut i32) (i32.const 0)) (global $exceptions/tryCatchFinallyResult (mut i32) (i32.const 0)) (global $exceptions/finallyWithExceptionRan (mut i32) (i32.const 0)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34504)) + (global $exceptions/deepNestingOrder (mut i32) (i32.const 1440)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 35596)) (memory $0 1) (data $0 (i32.const 1036) "<") (data $0.1 (i32.const 1048) "\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e") @@ -48,15 +49,74 @@ (data $14.1 (i32.const 1640) "\02\00\00\00\n\00\00\00e\00r\00r\00o\00r") (data $15 (i32.const 1660) ",") (data $15.1 (i32.const 1672) "\02\00\00\00\1c\00\00\00w\00i\00l\00l\00 \00p\00r\00o\00p\00a\00g\00a\00t\00e") - (data $16 (i32.const 1712) "\05\00\00\00 \00\00\00 \00\00\00 ") + (data $16 (i32.const 1708) "\1c") + (data $16.1 (i32.const 1720) "\02\00\00\00\0c\00\00\00c\00u\00s\00t\00o\00m") + (data $17 (i32.const 1740) ",") + (data $17.1 (i32.const 1752) "\02\00\00\00\16\00\00\00w\00o\00r\00k\00 \00f\00a\00i\00l\00e\00d") + (data $18 (i32.const 1788) "<") + (data $18.1 (i32.const 1800) "\02\00\00\00 \00\00\00d\00i\00v\00i\00s\00i\00o\00n\00 \00b\00y\00 \00z\00e\00r\00o") + (data $19 (i32.const 1852) ",") + (data $19.1 (i32.const 1864) "\02\00\00\00\16\00\00\00i\00n\00n\00e\00r\00 \00e\00r\00r\00o\00r") + (data $20 (i32.const 1900) ",") + (data $20.1 (i32.const 1912) "\02\00\00\00\1a\00\00\00w\00r\00a\00p\00p\00e\00d\00 \00e\00r\00r\00o\00r") + (data $21 (i32.const 1948) ",") + (data $21.1 (i32.const 1960) "\02\00\00\00\14\00\00\00R\00a\00n\00g\00e\00E\00r\00r\00o\00r") + (data $22 (i32.const 1996) ",") + (data $22.1 (i32.const 2008) "\02\00\00\00\1c\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00l\00e\00n\00g\00t\00h") + (data $23 (i32.const 2044) ",") + (data $23.1 (i32.const 2056) "\02\00\00\00\18\00\00\00s\00u\00m\00 \00e\00x\00c\00e\00e\00d\00e\00d") + (data $24 (i32.const 2092) ",") + (data $24.1 (i32.const 2104) "\02\00\00\00\10\00\00\00o\00r\00i\00g\00i\00n\00a\00l") + (data $25 (i32.const 2140) ",") + (data $25.1 (i32.const 2152) "\02\00\00\00\14\00\00\00r\00e\00t\00h\00r\00o\00w\00n\00:\00 ") + (data $26 (i32.const 2188) ",") + (data $26.1 (i32.const 2200) "\02\00\00\00\1a\00\00\00i\00n\00v\00a\00l\00i\00d\00 \00s\00t\00a\00t\00e") + (data $27 (i32.const 2236) "\1c") + (data $27.1 (i32.const 2248) "\02\00\00\00\06\00\00\00t\001\00,") + (data $28 (i32.const 2268) "\1c") + (data $28.1 (i32.const 2280) "\02\00\00\00\06\00\00\00t\002\00,") + (data $29 (i32.const 2300) "\1c") + (data $29.1 (i32.const 2312) "\02\00\00\00\06\00\00\00t\003\00,") + (data $30 (i32.const 2332) "\1c") + (data $30.1 (i32.const 2344) "\02\00\00\00\08\00\00\00d\00e\00e\00p") + (data $31 (i32.const 2364) "\1c") + (data $31.1 (i32.const 2376) "\02\00\00\00\06\00\00\00c\003\00,") + (data $32 (i32.const 2396) ",") + (data $32.1 (i32.const 2408) "\02\00\00\00\0e\00\00\00r\00e\00t\00h\00r\00o\00w") + (data $33 (i32.const 2444) "\1c") + (data $33.1 (i32.const 2456) "\02\00\00\00\06\00\00\00f\003\00,") + (data $34 (i32.const 2476) "\1c") + (data $34.1 (i32.const 2488) "\02\00\00\00\06\00\00\00c\002\00,") + (data $35 (i32.const 2508) "\1c") + (data $35.1 (i32.const 2520) "\02\00\00\00\06\00\00\00f\002\00,") + (data $36 (i32.const 2540) "\1c") + (data $36.1 (i32.const 2552) "\02\00\00\00\06\00\00\00c\001\00,") + (data $37 (i32.const 2572) "\1c") + (data $37.1 (i32.const 2584) "\02\00\00\00\06\00\00\00f\001\00,") + (data $38 (i32.const 2604) "L") + (data $38.1 (i32.const 2616) "\02\00\00\000\00\00\00t\001\00,\00t\002\00,\00t\003\00,\00c\003\00,\00f\003\00,\00c\002\00,\00f\002\00,\00f\001\00,") + (data $39 (i32.const 2684) ",") + (data $39.1 (i32.const 2696) "\02\00\00\00\16\00\00\00m\00a\00x\00 \00r\00e\00a\00c\00h\00e\00d") + (data $40 (i32.const 2732) "\1c") + (data $40.1 (i32.const 2744) "\02\00\00\00\08\00\00\00z\00e\00r\00o") + (data $41 (i32.const 2768) "\0e\00\00\00 \00\00\00 \00\00\00 ") + (data $41.1 (i32.const 2796) " \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 ") (tag $$error (type $0) (param i32)) (export "memory" (memory $0)) (start $~start) (func $~lib/rt/itcms/visitRoots (local $0 i32) (local $1 i32) + global.get $exceptions/deepNestingOrder + local.tee $0 + if + local.get $0 + call $~lib/rt/itcms/__visit + end i32.const 1248 call $~lib/rt/itcms/__visit + i32.const 2016 + call $~lib/rt/itcms/__visit i32.const 1056 call $~lib/rt/itcms/__visit global.get $~lib/rt/itcms/pinSpace @@ -120,7 +180,7 @@ local.get $1 global.set $~lib/rt/itcms/iter end - block $__inlined_func$~lib/rt/itcms/Object#unlink$131 + block $__inlined_func$~lib/rt/itcms/Object#unlink$239 local.get $0 i32.load offset=4 i32.const -4 @@ -132,7 +192,7 @@ i32.load offset=8 i32.eqz local.get $0 - i32.const 34504 + i32.const 35596 i32.lt_u i32.and i32.eqz @@ -144,7 +204,7 @@ call $~lib/builtins/abort unreachable end - br $__inlined_func$~lib/rt/itcms/Object#unlink$131 + br $__inlined_func$~lib/rt/itcms/Object#unlink$239 end local.get $0 i32.load offset=8 @@ -181,10 +241,11 @@ i32.const 1 else local.get $1 - i32.const 1712 + i32.const 2768 i32.load i32.gt_u if + i32.const 0 i32.const 1248 call $~lib/error/Error#constructor throw $$error @@ -192,7 +253,7 @@ local.get $1 i32.const 2 i32.shl - i32.const 1716 + i32.const 2772 i32.add i32.load i32.const 32 @@ -776,10 +837,10 @@ if unreachable end - i32.const 34512 + i32.const 35600 i32.const 0 i32.store - i32.const 36080 + i32.const 37168 i32.const 0 i32.store loop $for-loop|0 @@ -790,7 +851,7 @@ local.get $0 i32.const 2 i32.shl - i32.const 34512 + i32.const 35600 i32.add i32.const 0 i32.store offset=4 @@ -808,7 +869,7 @@ i32.add i32.const 2 i32.shl - i32.const 34512 + i32.const 35600 i32.add i32.const 0 i32.store offset=96 @@ -826,14 +887,14 @@ br $for-loop|0 end end - i32.const 34512 - i32.const 36084 + i32.const 35600 + i32.const 37172 memory.size i64.extend_i32_s i64.const 16 i64.shl call $~lib/rt/tlsf/addMemory - i32.const 34512 + i32.const 35600 global.set $~lib/rt/tlsf/ROOT ) (func $~lib/rt/itcms/step (result i32) @@ -918,7 +979,7 @@ local.set $0 loop $while-continue|0 local.get $0 - i32.const 34504 + i32.const 35596 i32.lt_u if local.get $0 @@ -1014,7 +1075,7 @@ unreachable end local.get $0 - i32.const 34504 + i32.const 35596 i32.lt_u if local.get $0 @@ -1037,7 +1098,7 @@ i32.const 4 i32.add local.tee $0 - i32.const 34504 + i32.const 35596 i32.ge_u if global.get $~lib/rt/tlsf/ROOT @@ -1096,18 +1157,85 @@ end i32.const 0 ) - (func $~lib/rt/tlsf/searchBlock (param $0 i32) (result i32) - (local $1 i32) + (func $~lib/rt/tlsf/searchBlock (param $0 i32) (param $1 i32) (result i32) (local $2 i32) + local.get $1 + i32.const 256 + i32.lt_u + if + local.get $1 + i32.const 4 + i32.shr_u + local.set $1 + else + local.get $1 + i32.const 536870910 + i32.lt_u + if + local.get $1 + i32.const 1 + i32.const 27 + local.get $1 + i32.clz + i32.sub + i32.shl + i32.add + i32.const 1 + i32.sub + local.set $1 + end + local.get $1 + i32.const 31 + local.get $1 + i32.clz + i32.sub + local.tee $2 + i32.const 4 + i32.sub + i32.shr_u + i32.const 16 + i32.xor + local.set $1 + local.get $2 + i32.const 7 + i32.sub + local.set $2 + end + local.get $1 + i32.const 16 + i32.lt_u + local.get $2 + i32.const 23 + i32.lt_u + i32.and + i32.eqz + if + i32.const 0 + i32.const 1344 + i32.const 334 + i32.const 14 + call $~lib/builtins/abort + unreachable + end local.get $0 + local.get $2 + i32.const 2 + i32.shl + i32.add i32.load offset=4 - i32.const -2 + i32.const -1 + local.get $1 + i32.shl i32.and local.tee $1 if (result i32) local.get $0 local.get $1 i32.ctz + local.get $2 + i32.const 4 + i32.shl + i32.add i32.const 2 i32.shl i32.add @@ -1115,19 +1243,23 @@ else local.get $0 i32.load - i32.const -2 + i32.const -1 + local.get $2 + i32.const 1 + i32.add + i32.shl i32.and local.tee $1 if (result i32) local.get $0 local.get $1 i32.ctz - local.tee $2 + local.tee $1 i32.const 2 i32.shl i32.add i32.load offset=4 - local.tee $1 + local.tee $2 i32.eqz if i32.const 0 @@ -1138,9 +1270,9 @@ unreachable end local.get $0 - local.get $1 - i32.ctz local.get $2 + i32.ctz + local.get $1 i32.const 4 i32.shl i32.add @@ -1153,23 +1285,33 @@ end end ) - (func $~lib/rt/itcms/__new (result i32) - (local $0 i32) - (local $1 i32) + (func $~lib/rt/itcms/__new (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741804 + i32.ge_u + if + i32.const 0 + i32.const 1056 + call $~lib/error/Error#constructor + throw $$error + end global.get $~lib/rt/itcms/total global.get $~lib/rt/itcms/threshold i32.ge_u if block $__inlined_func$~lib/rt/itcms/interrupt$69 i32.const 2048 - local.set $0 + local.set $2 loop $do-loop|0 - local.get $0 + local.get $2 call $~lib/rt/itcms/step i32.sub - local.set $0 + local.set $2 global.get $~lib/rt/itcms/state i32.eqz if @@ -1185,7 +1327,7 @@ global.set $~lib/rt/itcms/threshold br $__inlined_func$~lib/rt/itcms/interrupt$69 end - local.get $0 + local.get $2 i32.const 0 i32.gt_s br_if $do-loop|0 @@ -1208,39 +1350,92 @@ call $~lib/rt/tlsf/initialize end global.get $~lib/rt/tlsf/ROOT - local.tee $1 + local.set $4 + local.get $0 + i32.const 16 + i32.add + local.tee $2 + i32.const 1073741820 + i32.gt_u + if + i32.const 0 + i32.const 1056 + call $~lib/error/Error#constructor + throw $$error + end + local.get $4 + local.get $2 + i32.const 12 + i32.le_u + if (result i32) + i32.const 12 + else + local.get $2 + i32.const 19 + i32.add + i32.const -16 + i32.and + i32.const 4 + i32.sub + end + local.tee $5 call $~lib/rt/tlsf/searchBlock - local.tee $0 + local.tee $2 i32.eqz if memory.size - local.tee $0 + local.tee $2 + local.get $5 + i32.const 256 + i32.ge_u + if (result i32) + local.get $5 + i32.const 536870910 + i32.lt_u + if (result i32) + local.get $5 + i32.const 1 + i32.const 27 + local.get $5 + i32.clz + i32.sub + i32.shl + i32.add + i32.const 1 + i32.sub + else + local.get $5 + end + else + local.get $5 + end i32.const 4 - local.get $1 + local.get $4 i32.load offset=1568 - local.get $0 + local.get $2 i32.const 16 i32.shl i32.const 4 i32.sub i32.ne i32.shl - i32.const 65563 + i32.add + i32.const 65535 i32.add i32.const -65536 i32.and i32.const 16 i32.shr_u - local.tee $2 - local.get $0 + local.tee $3 local.get $2 + local.get $3 i32.gt_s select memory.grow i32.const 0 i32.lt_s if - local.get $2 + local.get $3 memory.grow i32.const 0 i32.lt_s @@ -1248,8 +1443,8 @@ unreachable end end - local.get $1 - local.get $0 + local.get $4 + local.get $2 i32.const 16 i32.shl memory.size @@ -1257,9 +1452,10 @@ i64.const 16 i64.shl call $~lib/rt/tlsf/addMemory - local.get $1 + local.get $4 + local.get $5 call $~lib/rt/tlsf/searchBlock - local.tee $0 + local.tee $2 i32.eqz if i32.const 0 @@ -1270,12 +1466,12 @@ unreachable end end - local.get $0 + local.get $5 + local.get $2 i32.load i32.const -4 i32.and - i32.const 28 - i32.lt_u + i32.gt_u if i32.const 0 i32.const 1344 @@ -1284,92 +1480,108 @@ call $~lib/builtins/abort unreachable end - local.get $1 - local.get $0 + local.get $4 + local.get $2 call $~lib/rt/tlsf/removeBlock - local.get $0 + local.get $2 i32.load - local.tee $2 + local.set $6 + local.get $5 + i32.const 4 + i32.add + i32.const 15 + i32.and + if + i32.const 0 + i32.const 1344 + i32.const 361 + i32.const 14 + call $~lib/builtins/abort + unreachable + end + local.get $6 i32.const -4 i32.and - i32.const 28 + local.get $5 i32.sub local.tee $3 i32.const 16 i32.ge_u if - local.get $0 local.get $2 + local.get $5 + local.get $6 i32.const 2 i32.and - i32.const 28 i32.or i32.store - local.get $0 - i32.const 32 + local.get $2 + i32.const 4 i32.add - local.tee $2 + local.get $5 + i32.add + local.tee $5 local.get $3 i32.const 4 i32.sub i32.const 1 i32.or i32.store - local.get $1 - local.get $2 + local.get $4 + local.get $5 call $~lib/rt/tlsf/insertBlock else - local.get $0 local.get $2 + local.get $6 i32.const -2 i32.and i32.store - local.get $0 + local.get $2 i32.const 4 i32.add - local.get $0 + local.get $2 i32.load i32.const -4 i32.and i32.add - local.tee $1 - local.get $1 + local.tee $3 + local.get $3 i32.load i32.const -3 i32.and i32.store end - local.get $0 - i32.const 4 + local.get $2 + local.get $1 i32.store offset=12 + local.get $2 local.get $0 - i32.const 12 i32.store offset=16 global.get $~lib/rt/itcms/fromSpace local.tee $1 i32.load offset=8 - local.set $2 - local.get $0 + local.set $3 + local.get $2 local.get $1 global.get $~lib/rt/itcms/white i32.or i32.store offset=4 - local.get $0 local.get $2 + local.get $3 i32.store offset=8 + local.get $3 local.get $2 - local.get $0 - local.get $2 + local.get $3 i32.load offset=4 i32.const 3 i32.and i32.or i32.store offset=4 local.get $1 - local.get $0 + local.get $2 i32.store offset=8 global.get $~lib/rt/itcms/total - local.get $0 + local.get $2 i32.load i32.const -4 i32.and @@ -1377,14 +1589,14 @@ i32.add i32.add global.set $~lib/rt/itcms/total - local.get $0 + local.get $2 i32.const 20 i32.add - local.tee $0 + local.tee $1 i32.const 0 - i32.const 12 - memory.fill local.get $0 + memory.fill + local.get $1 ) (func $~lib/rt/itcms/__link (param $0 i32) (param $1 i32) local.get $1 @@ -1441,43 +1653,165 @@ end ) (func $~lib/rt/__visit_members (param $0 i32) - block $invalid - block $~lib/error/Error - block $~lib/arraybuffer/ArrayBufferView - block $~lib/string/String - block $~lib/arraybuffer/ArrayBuffer - block $~lib/object/Object + block $folding-inner0 + block $invalid + block $exceptions/Counter + block $exceptions/StateMachine + block $~lib/array/Array + block $exceptions/Inner + block $exceptions/Outer + block $exceptions/Calculator + block $exceptions/Resource + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + block $~lib/object/Object + local.get $0 + i32.const 8 + i32.sub + i32.load + br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $folding-inner0 $folding-inner0 $exceptions/Resource $exceptions/Calculator $exceptions/Outer $exceptions/Inner $~lib/array/Array $folding-inner0 $exceptions/StateMachine $exceptions/Counter $invalid + end + return + end + return + end + return + end + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + return + end + return + end + return + end local.get $0 - i32.const 8 - i32.sub i32.load - br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/error/Error $invalid + call $~lib/rt/itcms/__visit + return end return end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 2828 + i32.lt_s + if + i32.const 35616 + i32.const 35664 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer return end return end - local.get $0 - i32.load - call $~lib/rt/itcms/__visit return end - local.get $0 - i32.load - call $~lib/rt/itcms/__visit - local.get $0 - i32.load offset=4 - call $~lib/rt/itcms/__visit - local.get $0 - i32.load offset=8 - call $~lib/rt/itcms/__visit - return + unreachable end - unreachable + local.get $0 + i32.load + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=4 + call $~lib/rt/itcms/__visit + local.get $0 + i32.load offset=8 + call $~lib/rt/itcms/__visit ) (func $~start + call $start:exceptions + ) + (func $~lib/error/Error#constructor (param $0 i32) (param $1 i32) (result i32) + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 2828 + i32.lt_s + if + i32.const 35616 + i32.const 35664 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i64.const 0 + i64.store + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store offset=8 + local.get $0 + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.const 4 + call $~lib/rt/itcms/__new + local.tee $0 + i32.store + end + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store offset=4 + global.get $~lib/memory/__stack_pointer + local.get $1 + i32.store offset=8 + local.get $0 + local.get $1 + i32.store offset=8 + local.get $0 + local.get $1 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store offset=4 + local.get $0 + i32.const 1408 + i32.store + local.get $0 + i32.const 1408 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store offset=4 + local.get $0 + i32.const 1440 + i32.store offset=4 + local.get $0 + i32.const 1440 + call $~lib/rt/itcms/__link + global.get $~lib/memory/__stack_pointer + i32.const 12 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $0 + ) + (func $start:exceptions (local $0 i32) (local $1 i32) (local $2 i32) @@ -1489,11 +1823,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1736 + i32.const 2828 i32.lt_s if - i32.const 34528 - i32.const 34576 + i32.const 35616 + i32.const 35664 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1505,7 +1839,7 @@ memory.size i32.const 16 i32.shl - i32.const 34504 + i32.const 35596 i32.sub i32.const 1 i32.shr_u @@ -1534,15 +1868,16 @@ i32.store i32.const 1296 global.set $~lib/rt/itcms/fromSpace - block $__inlined_func$exceptions/testTryCatch$121 + block $__inlined_func$exceptions/testTryCatch$165 try + i32.const 0 i32.const 1472 call $~lib/error/Error#constructor throw $$error catch $$error drop - br $__inlined_func$exceptions/testTryCatch$121 + br $__inlined_func$exceptions/testTryCatch$165 end unreachable end @@ -1551,11 +1886,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1736 + i32.const 2828 i32.lt_s if - i32.const 34528 - i32.const 34576 + i32.const 35616 + i32.const 35664 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1564,8 +1899,9 @@ global.get $~lib/memory/__stack_pointer i32.const 0 i32.store - block $__inlined_func$exceptions/testCatchVar$122 + block $__inlined_func$exceptions/testCatchVar$230 try + i32.const 0 i32.const 1552 call $~lib/error/Error#constructor throw $$error @@ -1582,24 +1918,24 @@ i32.const 4 i32.add global.set $~lib/memory/__stack_pointer - br $__inlined_func$exceptions/testCatchVar$122 + br $__inlined_func$exceptions/testCatchVar$230 end unreachable end global.get $~lib/memory/__stack_pointer local.get $5 i32.store - block $__inlined_func$~lib/string/String.__eq$1 (result i32) + block $__inlined_func$~lib/string/String.__eq$2 (result i32) global.get $~lib/memory/__stack_pointer i32.const 8 i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1736 + i32.const 2828 i32.lt_s if - i32.const 34528 - i32.const 34576 + i32.const 35616 + i32.const 35664 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1617,7 +1953,7 @@ i32.add global.set $~lib/memory/__stack_pointer i32.const 1 - br $__inlined_func$~lib/string/String.__eq$1 + br $__inlined_func$~lib/string/String.__eq$2 end block $folding-inner0 local.get $5 @@ -1686,7 +2022,7 @@ end end end - block $__inlined_func$~lib/util/string/compareImpl$85 + block $__inlined_func$~lib/util/string/compareImpl$94 loop $while-continue|1 local.get $1 local.tee $0 @@ -1706,7 +2042,7 @@ local.get $0 local.get $2 i32.ne - br_if $__inlined_func$~lib/util/string/compareImpl$85 + br_if $__inlined_func$~lib/util/string/compareImpl$94 local.get $5 i32.const 2 i32.add @@ -1727,7 +2063,7 @@ global.set $~lib/memory/__stack_pointer local.get $4 i32.eqz - br $__inlined_func$~lib/string/String.__eq$1 + br $__inlined_func$~lib/string/String.__eq$2 end global.get $~lib/memory/__stack_pointer i32.const 8 @@ -1744,15 +2080,17 @@ call $~lib/builtins/abort unreachable end - block $__inlined_func$exceptions/testNested$125 + block $__inlined_func$exceptions/testNested$168 try try + i32.const 0 i32.const 1584 call $~lib/error/Error#constructor throw $$error catch $$error drop + i32.const 0 i32.const 1616 call $~lib/error/Error#constructor throw $$error @@ -1761,12 +2099,31 @@ catch $$error drop - br $__inlined_func$exceptions/testNested$125 + br $__inlined_func$exceptions/testNested$168 + end + unreachable + end + block $finally_dispatch|02 + try $try_finally|03 + try + i32.const 0 + i32.const 1648 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + drop + br $finally_dispatch|02 + end + unreachable + catch_all + rethrow $try_finally|03 end unreachable end - try $try_finally|07 + try $try_finally|06 try + i32.const 0 i32.const 1648 call $~lib/error/Error#constructor throw $$error @@ -1779,7 +2136,7 @@ catch_all i32.const 1 global.set $exceptions/tryCatchFinallyRan - rethrow $try_finally|07 + rethrow $try_finally|06 end i32.const 1 global.set $exceptions/tryCatchFinallyRan @@ -1789,7 +2146,7 @@ if i32.const 0 i32.const 1504 - i32.const 78 + i32.const 92 i32.const 1 call $~lib/builtins/abort unreachable @@ -1800,21 +2157,22 @@ if i32.const 0 i32.const 1504 - i32.const 79 + i32.const 93 i32.const 1 call $~lib/builtins/abort unreachable end - block $__inlined_func$exceptions/testFinallyWithException$127 + block $__inlined_func$exceptions/testFinallyWithException$231 try - try $try_finally|010 + try $try_finally|07 + i32.const 0 i32.const 1680 call $~lib/error/Error#constructor throw $$error catch_all i32.const 1 global.set $exceptions/finallyWithExceptionRan - rethrow $try_finally|010 + rethrow $try_finally|07 end unreachable catch $$error @@ -1824,7 +2182,7 @@ i32.const 0 i32.ne local.set $0 - br $__inlined_func$exceptions/testFinallyWithException$127 + br $__inlined_func$exceptions/testFinallyWithException$231 end unreachable end @@ -1833,77 +2191,11 @@ if i32.const 0 i32.const 1504 - i32.const 98 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - global.get $~lib/memory/__stack_pointer - i32.const 4 - i32.add - global.set $~lib/memory/__stack_pointer - ) - (func $~lib/error/Error#constructor (param $0 i32) (result i32) - (local $1 i32) - global.get $~lib/memory/__stack_pointer - i32.const 12 - i32.sub - global.set $~lib/memory/__stack_pointer - global.get $~lib/memory/__stack_pointer - i32.const 1736 - i32.lt_s - if - i32.const 34528 - i32.const 34576 - i32.const 1 + i32.const 112 i32.const 1 call $~lib/builtins/abort unreachable end - global.get $~lib/memory/__stack_pointer - i64.const 0 - i64.store - global.get $~lib/memory/__stack_pointer - i32.const 0 - i32.store offset=8 - global.get $~lib/memory/__stack_pointer - call $~lib/rt/itcms/__new - local.tee $1 - i32.store - global.get $~lib/memory/__stack_pointer - local.get $1 - i32.store offset=4 - global.get $~lib/memory/__stack_pointer - local.get $0 - i32.store offset=8 - local.get $1 - local.get $0 - i32.store offset=8 - local.get $1 - local.get $0 - call $~lib/rt/itcms/__link - global.get $~lib/memory/__stack_pointer - local.get $1 - i32.store offset=4 - local.get $1 - i32.const 1408 - i32.store - local.get $1 - i32.const 1408 - call $~lib/rt/itcms/__link - global.get $~lib/memory/__stack_pointer - local.get $1 - i32.store offset=4 - local.get $1 - i32.const 1440 - i32.store offset=4 - local.get $1 - i32.const 1440 - call $~lib/rt/itcms/__link - global.get $~lib/memory/__stack_pointer - i32.const 12 - i32.add - global.set $~lib/memory/__stack_pointer - local.get $1 + unreachable ) ) diff --git a/tests/compiler/exceptions.ts b/tests/compiler/exceptions.ts index e0c0e70421..e95151df48 100644 --- a/tests/compiler/exceptions.ts +++ b/tests/compiler/exceptions.ts @@ -62,6 +62,20 @@ function testNested(): i32 { } assert(testNested() == 42); +// Try-catch-finally with return in catch - finally must run before return +let returnInCatchFinallyRan = false; +function testReturnInCatchFinally(): i32 { + try { + throw new Error("error"); + } catch (e) { + return 10; // Return in catch - finally must run first! + } finally { + returnInCatchFinallyRan = true; + } +} +assert(testReturnInCatchFinally() == 10); +assert(returnInCatchFinallyRan == true); + // Try-catch-finally (without return in catch) let tryCatchFinallyRan = false; let tryCatchFinallyResult = 0; @@ -108,3 +122,342 @@ function testFinallyNormalCompletion(): i32 { return finallyNormalRan ? 1 : 0; } assert(testFinallyNormalCompletion() == 1); + +// ============================================================================ +// Complex tests with classes +// ============================================================================ + +// Custom error class extending Error +class CustomError extends Error { + constructor(message: string, public code: i32) { + super(message); + } +} + +// Test throwing custom error +function testCustomError(): i32 { + try { + throw new CustomError("custom", 42); + } catch (e) { + // e is Error type, but carries CustomError data + return 1; + } + return 0; +} +assert(testCustomError() == 1); + +// Resource management class +class Resource { + static instances: i32 = 0; + static disposed: i32 = 0; + + id: i32; + + constructor() { + this.id = ++Resource.instances; + } + + dispose(): void { + Resource.disposed++; + } + + doWork(): void { + // Might throw + } + + doWorkThatThrows(): void { + throw new Error("work failed"); + } +} + +// Test resource cleanup in finally +function testResourceCleanup(): i32 { + let r = new Resource(); + let result: i32 = 0; + try { + r.doWork(); + result = 1; + } finally { + r.dispose(); + } + return result; +} +assert(testResourceCleanup() == 1); +assert(Resource.disposed == 1); + +// Test resource cleanup when exception thrown +function testResourceCleanupWithException(): i32 { + Resource.disposed = 0; // Reset + let r = new Resource(); + try { + try { + r.doWorkThatThrows(); + } finally { + r.dispose(); + } + } catch (e) { + return Resource.disposed; // Should be 1 - disposed even though exception + } + return 0; +} +assert(testResourceCleanupWithException() == 1); + +// Class with method that uses try-catch +class Calculator { + value: i32 = 0; + + divide(a: i32, b: i32): i32 { + try { + if (b == 0) { + throw new Error("division by zero"); + } + return a / b; + } catch (e) { + this.value = -1; // Mark error state + return 0; + } + } + + safeDivide(a: i32, b: i32): i32 { + try { + if (b == 0) { + throw new Error("division by zero"); + } + this.value = a / b; + return this.value; + } catch (e) { + return -1; + } finally { + // Always runs - could log or cleanup + } + } +} + +let calc = new Calculator(); +assert(calc.divide(10, 2) == 5); +assert(calc.divide(10, 0) == 0); +assert(calc.value == -1); + +calc.value = 0; +assert(calc.safeDivide(20, 4) == 5); +assert(calc.safeDivide(20, 0) == -1); + +// Nested class exception handling +class Outer { + inner: Inner; + + constructor() { + this.inner = new Inner(); + } + + process(): i32 { + try { + return this.inner.riskyOperation(); + } catch (e) { + return -1; + } + } +} + +class Inner { + riskyOperation(): i32 { + try { + throw new Error("inner error"); + } catch (e) { + throw new Error("wrapped error"); + } + return 0; + } +} + +let outer = new Outer(); +assert(outer.process() == -1); + +// Array operations with exceptions +function testArrayWithExceptions(): i32 { + let arr = new Array(3); + arr[0] = 1; + arr[1] = 2; + arr[2] = 3; + + let sum: i32 = 0; + try { + for (let i = 0; i < arr.length; i++) { + sum += arr[i]; + if (sum > 5) { + throw new Error("sum exceeded"); + } + } + } catch (e) { + return sum; // Should be 6 (1+2+3) + } + return 0; +} +assert(testArrayWithExceptions() == 6); + +// Multiple catch scenarios with rethrow +let rethrowFinallyRan = false; +function innerRethrow(): void { + try { + throw new Error("original"); + } catch (e) { + rethrowFinallyRan = false; + throw new Error("rethrown: " + e.message); + } finally { + rethrowFinallyRan = true; + } +} + +function testRethrowWithFinally(): i32 { + rethrowFinallyRan = false; + try { + innerRethrow(); + } catch (e) { + // Check that finally ran even during rethrow + return rethrowFinallyRan ? 1 : 0; + } + return 0; +} +assert(testRethrowWithFinally() == 1); + +// State machine with exceptions +class StateMachine { + state: i32 = 0; + errorState: bool = false; + + transition(newState: i32): void { + try { + if (newState < 0) { + throw new Error("invalid state"); + } + this.state = newState; + } catch (e) { + this.errorState = true; + this.state = -1; + } + } + + reset(): void { + try { + this.state = 0; + this.errorState = false; + } finally { + // Cleanup any resources + } + } +} + +let sm = new StateMachine(); +sm.transition(1); +assert(sm.state == 1); +assert(sm.errorState == false); + +sm.transition(-5); +assert(sm.state == -1); +assert(sm.errorState == true); + +sm.reset(); +assert(sm.state == 0); +assert(sm.errorState == false); + +// Deeply nested try-catch-finally +let deepNestingOrder: string = ""; + +function testDeepNesting(): i32 { + deepNestingOrder = ""; + try { + deepNestingOrder += "t1,"; + try { + deepNestingOrder += "t2,"; + try { + deepNestingOrder += "t3,"; + throw new Error("deep"); + } catch (e) { + deepNestingOrder += "c3,"; + throw new Error("rethrow"); + } finally { + deepNestingOrder += "f3,"; + } + } catch (e) { + deepNestingOrder += "c2,"; + } finally { + deepNestingOrder += "f2,"; + } + } catch (e) { + deepNestingOrder += "c1,"; + } finally { + deepNestingOrder += "f1,"; + } + return 1; +} +assert(testDeepNesting() == 1); +assert(deepNestingOrder == "t1,t2,t3,c3,f3,c2,f2,f1,"); + +// Counter class (alternative to closure) +class Counter { + count: i32 = 0; + + increment(): i32 { + try { + this.count++; + if (this.count > 3) { + throw new Error("max reached"); + } + return this.count; + } catch (e) { + return -1; + } + } +} + +let counter = new Counter(); +assert(counter.increment() == 1); +assert(counter.increment() == 2); +assert(counter.increment() == 3); +assert(counter.increment() == -1); // 4th call throws and catches + +// Return value from try block (not catch) +function testReturnFromTry(): i32 { + try { + return 42; + } catch (e) { + return -1; + } finally { + // This runs before the return from try + } +} +assert(testReturnFromTry() == 42); + +// Multiple returns with finally +let multiReturnFinallyCount = 0; +function testMultipleReturnsWithFinally(x: i32): i32 { + try { + if (x < 0) { + return -1; + } + if (x == 0) { + throw new Error("zero"); + } + if (x > 100) { + return 100; + } + return x; + } catch (e) { + return 0; + } finally { + multiReturnFinallyCount++; + } +} + +multiReturnFinallyCount = 0; +assert(testMultipleReturnsWithFinally(-5) == -1); +assert(multiReturnFinallyCount == 1); + +assert(testMultipleReturnsWithFinally(0) == 0); +assert(multiReturnFinallyCount == 2); + +assert(testMultipleReturnsWithFinally(50) == 50); +assert(multiReturnFinallyCount == 3); + +assert(testMultipleReturnsWithFinally(200) == 100); +assert(multiReturnFinallyCount == 4); From 3b50df4e1eeb46116884d50f540b14a0dcbd1319 Mon Sep 17 00:00:00 2001 From: BlobMaster41 <96896824+BlobMaster41@users.noreply.github.com> Date: Thu, 11 Dec 2025 00:36:37 -0500 Subject: [PATCH 3/3] Handle return/termination in finally blocks for try-catch-finally Updates the compiler to detect if a finally block always returns or terminates, and skips dispatch logic accordingly. Adds tests to verify that return statements in finally blocks override returns in try/catch and suppress exceptions. --- src/compiler.ts | 60 +++++++----- tests/compiler/exceptions.debug.wat | 131 ++++++++++++++++++++++++-- tests/compiler/exceptions.release.wat | 80 ++++++++-------- tests/compiler/exceptions.ts | 35 +++++++ 4 files changed, 237 insertions(+), 69 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 4f1cee5026..34e24fddda 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -3368,6 +3368,8 @@ export class Compiler extends DiagnosticEmitter { let finallyStmts2 = new Array(); this.compileStatements(finallyStatements, finallyStmts2); let finallyExpr2 = module.flatten(finallyStmts2); + let finallyTerminates = finallyFlow2.isAny(FlowFlags.Terminates); + let finallyReturns = finallyFlow2.isAny(FlowFlags.Returns); this.currentFlow = outerFlow; outerFlow.popControlFlowLabel(label2); @@ -3378,28 +3380,31 @@ export class Compiler extends DiagnosticEmitter { // Run finally code dispatchStmts.push(finallyExpr2); - // Dispatch based on pendingAction - // if (pendingAction == 1) return pendingValue; - if (returnType != Type.void && pendingValueLocal) { - dispatchStmts.push( - module.if( - module.binary(BinaryOp.EqI32, - module.local_get(pendingActionLocal.index, TypeRef.I32), - module.i32(1) - ), - module.return(module.local_get(pendingValueLocal.index, returnType.toRef())) - ) - ); - } else { - dispatchStmts.push( - module.if( - module.binary(BinaryOp.EqI32, - module.local_get(pendingActionLocal.index, TypeRef.I32), - module.i32(1) - ), - module.return() - ) - ); + // If finally always returns/terminates, skip dispatch logic + if (!finallyTerminates) { + // Dispatch based on pendingAction + // if (pendingAction == 1) return pendingValue; + if (returnType != Type.void && pendingValueLocal) { + dispatchStmts.push( + module.if( + module.binary(BinaryOp.EqI32, + module.local_get(pendingActionLocal.index, TypeRef.I32), + module.i32(1) + ), + module.return(module.local_get(pendingValueLocal.index, returnType.toRef())) + ) + ); + } else { + dispatchStmts.push( + module.if( + module.binary(BinaryOp.EqI32, + module.local_get(pendingActionLocal.index, TypeRef.I32), + module.i32(1) + ), + module.return() + ) + ); + } } // The full structure: @@ -3418,7 +3423,8 @@ export class Compiler extends DiagnosticEmitter { // For functions that return a value, add unreachable at the end // This handles the case where normal completion didn't have a return // (in theory this path shouldn't be reachable if all paths return) - if (returnType != Type.void) { + // But skip if finally already terminates + if (returnType != Type.void && !finallyTerminates) { dispatchStmts.push(module.unreachable()); } @@ -3428,7 +3434,13 @@ export class Compiler extends DiagnosticEmitter { ]); // Merge flow states - if (catchFlow) { + // If finally always terminates, the whole construct terminates + if (finallyTerminates) { + outerFlow.set(FlowFlags.Terminates); + if (finallyReturns) { + outerFlow.set(FlowFlags.Returns); + } + } else if (catchFlow) { if (tryFlowTerminates && catchFlowTerminates) { outerFlow.set(FlowFlags.Terminates); } else { diff --git a/tests/compiler/exceptions.debug.wat b/tests/compiler/exceptions.debug.wat index 53943ed906..966899942c 100644 --- a/tests/compiler/exceptions.debug.wat +++ b/tests/compiler/exceptions.debug.wat @@ -42,10 +42,11 @@ (global $exceptions/deepNestingOrder (mut i32) (i32.const 416)) (global $exceptions/counter (mut i32) (i32.const 0)) (global $exceptions/multiReturnFinallyCount (mut i32) (i32.const 0)) - (global $~lib/rt/__rtti_base i32 (i32.const 1744)) - (global $~lib/memory/__data_end i32 (i32.const 1804)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34572)) - (global $~lib/memory/__heap_base i32 (i32.const 34572)) + (global $exceptions/finallyReturnSuppressedExceptionRan (mut i32) (i32.const 0)) + (global $~lib/rt/__rtti_base i32 (i32.const 1840)) + (global $~lib/memory/__data_end i32 (i32.const 1900)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 34668)) + (global $~lib/memory/__heap_base i32 (i32.const 34668)) (memory $0 1) (data $0 (i32.const 12) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e\00\00\00\00\00") (data $1 (i32.const 80) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") @@ -88,7 +89,9 @@ (data $38 (i32.const 1580) "L\00\00\00\00\00\00\00\00\00\00\00\02\00\00\000\00\00\00t\001\00,\00t\002\00,\00t\003\00,\00c\003\00,\00f\003\00,\00c\002\00,\00f\002\00,\00f\001\00,\00\00\00\00\00\00\00\00\00\00\00\00\00") (data $39 (i32.const 1660) ",\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\16\00\00\00m\00a\00x\00 \00r\00e\00a\00c\00h\00e\00d\00\00\00\00\00\00\00") (data $40 (i32.const 1708) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\08\00\00\00z\00e\00r\00o\00\00\00\00\00") - (data $41 (i32.const 1744) "\0e\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 \00\00\00") + (data $41 (i32.const 1740) "\1c\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\08\00\00\00t\00e\00s\00t\00\00\00\00\00") + (data $42 (i32.const 1772) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00(\00\00\00s\00h\00o\00u\00l\00d\00 \00b\00e\00 \00s\00u\00p\00p\00r\00e\00s\00s\00e\00d\00\00\00\00\00") + (data $43 (i32.const 1840) "\0e\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 \00\00\00") (table $0 1 1 funcref) (elem $0 (i32.const 1)) (tag $$error (type $3) (param i32)) @@ -3024,6 +3027,72 @@ end unreachable ) + (func $exceptions/testReturnInFinally (result i32) + (local $0 i32) + (local $1 i32) + block $finally_dispatch|0 + try $try_finally|0 + i32.const 1 + local.set $1 + i32.const 1 + local.set $0 + br $finally_dispatch|0 + catch_all + i32.const 2 + return + end + unreachable + end + i32.const 2 + return + ) + (func $exceptions/testReturnInFinallyOverridesCatch (result i32) + (local $e i32) + (local $1 i32) + (local $2 i32) + (local $e|3 i32) + block $finally_dispatch|0 + try $try_finally|0 + try $try|1 + i32.const 0 + i32.const 1760 + call $~lib/error/Error#constructor + throw $$error + catch $$error + + local.set $e|3 + i32.const 1 + local.set $2 + i32.const 1 + local.set $1 + br $finally_dispatch|0 + end + unreachable + catch_all + i32.const 2 + return + end + unreachable + end + i32.const 2 + return + ) + (func $exceptions/testReturnInFinallySuppressesException (result i32) + (local $0 i32) + (local $1 i32) + try $try_finally|0 + i32.const 0 + i32.const 1792 + call $~lib/error/Error#constructor + throw $$error + catch_all + i32.const 1 + global.set $exceptions/finallyReturnSuppressedExceptionRan + i32.const 42 + return + end + unreachable + ) (func $~lib/rt/__visit_globals (param $0 i32) (local $1 i32) global.get $exceptions/calc @@ -3211,8 +3280,8 @@ global.get $~lib/memory/__data_end i32.lt_s if - i32.const 34592 - i32.const 34640 + i32.const 34688 + i32.const 34736 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -5893,6 +5962,54 @@ call $~lib/builtins/abort unreachable end + call $exceptions/testReturnInFinally + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 473 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testReturnInFinallyOverridesCatch + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 485 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $exceptions/testReturnInFinallySuppressesException + i32.const 42 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 497 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $exceptions/finallyReturnSuppressedExceptionRan + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 480 + i32.const 498 + i32.const 1 + call $~lib/builtins/abort + unreachable + end global.get $~lib/memory/__stack_pointer i32.const 4 i32.add diff --git a/tests/compiler/exceptions.release.wat b/tests/compiler/exceptions.release.wat index d2fc247867..21e70f6c35 100644 --- a/tests/compiler/exceptions.release.wat +++ b/tests/compiler/exceptions.release.wat @@ -21,7 +21,7 @@ (global $exceptions/tryCatchFinallyResult (mut i32) (i32.const 0)) (global $exceptions/finallyWithExceptionRan (mut i32) (i32.const 0)) (global $exceptions/deepNestingOrder (mut i32) (i32.const 1440)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 35596)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 35692)) (memory $0 1) (data $0 (i32.const 1036) "<") (data $0.1 (i32.const 1048) "\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e") @@ -99,8 +99,12 @@ (data $39.1 (i32.const 2696) "\02\00\00\00\16\00\00\00m\00a\00x\00 \00r\00e\00a\00c\00h\00e\00d") (data $40 (i32.const 2732) "\1c") (data $40.1 (i32.const 2744) "\02\00\00\00\08\00\00\00z\00e\00r\00o") - (data $41 (i32.const 2768) "\0e\00\00\00 \00\00\00 \00\00\00 ") - (data $41.1 (i32.const 2796) " \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 ") + (data $41 (i32.const 2764) "\1c") + (data $41.1 (i32.const 2776) "\02\00\00\00\08\00\00\00t\00e\00s\00t") + (data $42 (i32.const 2796) "<") + (data $42.1 (i32.const 2808) "\02\00\00\00(\00\00\00s\00h\00o\00u\00l\00d\00 \00b\00e\00 \00s\00u\00p\00p\00r\00e\00s\00s\00e\00d") + (data $43 (i32.const 2864) "\0e\00\00\00 \00\00\00 \00\00\00 ") + (data $43.1 (i32.const 2892) " \00\00\00 \00\00\00\00\00\00\00 \00\00\00\02\t\00\00\00\00\00\00 \00\00\00 ") (tag $$error (type $0) (param i32)) (export "memory" (memory $0)) (start $~start) @@ -180,7 +184,7 @@ local.get $1 global.set $~lib/rt/itcms/iter end - block $__inlined_func$~lib/rt/itcms/Object#unlink$239 + block $__inlined_func$~lib/rt/itcms/Object#unlink$242 local.get $0 i32.load offset=4 i32.const -4 @@ -192,7 +196,7 @@ i32.load offset=8 i32.eqz local.get $0 - i32.const 35596 + i32.const 35692 i32.lt_u i32.and i32.eqz @@ -204,7 +208,7 @@ call $~lib/builtins/abort unreachable end - br $__inlined_func$~lib/rt/itcms/Object#unlink$239 + br $__inlined_func$~lib/rt/itcms/Object#unlink$242 end local.get $0 i32.load offset=8 @@ -241,7 +245,7 @@ i32.const 1 else local.get $1 - i32.const 2768 + i32.const 2864 i32.load i32.gt_u if @@ -253,7 +257,7 @@ local.get $1 i32.const 2 i32.shl - i32.const 2772 + i32.const 2868 i32.add i32.load i32.const 32 @@ -837,10 +841,10 @@ if unreachable end - i32.const 35600 + i32.const 35696 i32.const 0 i32.store - i32.const 37168 + i32.const 37264 i32.const 0 i32.store loop $for-loop|0 @@ -851,7 +855,7 @@ local.get $0 i32.const 2 i32.shl - i32.const 35600 + i32.const 35696 i32.add i32.const 0 i32.store offset=4 @@ -869,7 +873,7 @@ i32.add i32.const 2 i32.shl - i32.const 35600 + i32.const 35696 i32.add i32.const 0 i32.store offset=96 @@ -887,14 +891,14 @@ br $for-loop|0 end end - i32.const 35600 - i32.const 37172 + i32.const 35696 + i32.const 37268 memory.size i64.extend_i32_s i64.const 16 i64.shl call $~lib/rt/tlsf/addMemory - i32.const 35600 + i32.const 35696 global.set $~lib/rt/tlsf/ROOT ) (func $~lib/rt/itcms/step (result i32) @@ -979,7 +983,7 @@ local.set $0 loop $while-continue|0 local.get $0 - i32.const 35596 + i32.const 35692 i32.lt_u if local.get $0 @@ -1075,7 +1079,7 @@ unreachable end local.get $0 - i32.const 35596 + i32.const 35692 i32.lt_u if local.get $0 @@ -1098,7 +1102,7 @@ i32.const 4 i32.add local.tee $0 - i32.const 35596 + i32.const 35692 i32.ge_u if global.get $~lib/rt/tlsf/ROOT @@ -1699,11 +1703,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 2828 + i32.const 2924 i32.lt_s if - i32.const 35616 - i32.const 35664 + i32.const 35712 + i32.const 35760 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1749,11 +1753,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 2828 + i32.const 2924 i32.lt_s if - i32.const 35616 - i32.const 35664 + i32.const 35712 + i32.const 35760 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1823,11 +1827,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 2828 + i32.const 2924 i32.lt_s if - i32.const 35616 - i32.const 35664 + i32.const 35712 + i32.const 35760 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1839,7 +1843,7 @@ memory.size i32.const 16 i32.shl - i32.const 35596 + i32.const 35692 i32.sub i32.const 1 i32.shr_u @@ -1886,11 +1890,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 2828 + i32.const 2924 i32.lt_s if - i32.const 35616 - i32.const 35664 + i32.const 35712 + i32.const 35760 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -1899,7 +1903,7 @@ global.get $~lib/memory/__stack_pointer i32.const 0 i32.store - block $__inlined_func$exceptions/testCatchVar$230 + block $__inlined_func$exceptions/testCatchVar$233 try i32.const 0 i32.const 1552 @@ -1918,7 +1922,7 @@ i32.const 4 i32.add global.set $~lib/memory/__stack_pointer - br $__inlined_func$exceptions/testCatchVar$230 + br $__inlined_func$exceptions/testCatchVar$233 end unreachable end @@ -1931,11 +1935,11 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 2828 + i32.const 2924 i32.lt_s if - i32.const 35616 - i32.const 35664 + i32.const 35712 + i32.const 35760 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -2162,7 +2166,7 @@ call $~lib/builtins/abort unreachable end - block $__inlined_func$exceptions/testFinallyWithException$231 + block $__inlined_func$exceptions/testFinallyWithException$234 try try $try_finally|07 i32.const 0 @@ -2182,7 +2186,7 @@ i32.const 0 i32.ne local.set $0 - br $__inlined_func$exceptions/testFinallyWithException$231 + br $__inlined_func$exceptions/testFinallyWithException$234 end unreachable end diff --git a/tests/compiler/exceptions.ts b/tests/compiler/exceptions.ts index e95151df48..f0eb75a0da 100644 --- a/tests/compiler/exceptions.ts +++ b/tests/compiler/exceptions.ts @@ -461,3 +461,38 @@ assert(multiReturnFinallyCount == 3); assert(testMultipleReturnsWithFinally(200) == 100); assert(multiReturnFinallyCount == 4); + +// Return in finally overrides return in try +function testReturnInFinally(): i32 { + try { + return 1; // This return is overridden + } finally { + return 2; // This return wins + } +} +assert(testReturnInFinally() == 2); + +// Return in finally overrides return in catch +function testReturnInFinallyOverridesCatch(): i32 { + try { + throw new Error("test"); + } catch (e) { + return 1; // This return is overridden + } finally { + return 2; // This return wins + } +} +assert(testReturnInFinallyOverridesCatch() == 2); + +// Return in finally suppresses exception +let finallyReturnSuppressedExceptionRan = false; +function testReturnInFinallySuppressesException(): i32 { + try { + throw new Error("should be suppressed"); + } finally { + finallyReturnSuppressedExceptionRan = true; + return 42; // This suppresses the exception + } +} +assert(testReturnInFinallySuppressesException() == 42); +assert(finallyReturnSuppressedExceptionRan == true);