forked from AssemblyScript/assemblyscript
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Implement WebAssembly exception handling (try-catch-finally) #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
BlobMaster41
wants to merge
23
commits into
main
Choose a base branch
from
try-catch-finally
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Adds closure environment allocation, variable capture analysis, and code generation for accessing and storing captured variables in closures. Updates the compiler to prescan function bodies for captured variables, allocate and initialize closure environments, and handle closure function creation and invocation. Extends Flow and Function/Local classes to track closure-related metadata. Includes new tests for closure behavior.
Corrects the calculation of environment slot offsets for captured variables in closures, ensuring proper byte offset handling and consistent environment setup. Updates test WAT files to reflect the new closure environment layout and stack management, improving correctness and coverage for closure, function expression, return, ternary, and typealias scenarios.
Enhances closure support by properly aligning captured local offsets, caching the closure environment pointer in a local to prevent overwrites from indirect calls, and updating environment size calculations. Also adds comprehensive AST node coverage for captured variable analysis and updates related tests to reflect the new closure environment management.
Adds logic to prescan constructor arguments of 'new' expressions for function expressions. This ensures that any function expressions passed as arguments are properly processed during compilation.
Introduce new test files for closure class functionality in the compiler, including TypeScript source, expected JSON output, and debug/release WebAssembly text formats.
Introduces a new 'closures' feature flag to the compiler, updates feature enumeration, and adds checks to ensure closures are only used when the feature is enabled. Test configurations are updated to enable the closures feature for relevant tests.
Refactored the compiler to only emit closure environment setup code when the closures feature is enabled. For builds without closures, indirect calls now use a simpler code path, resulting in smaller and cleaner generated code. Updated numerous test outputs to reflect the reduced stack usage and removed unnecessary closure environment handling.
Reserve slot 0 in closure environments for the parent environment pointer, ensuring correct alignment and traversal for nested closures. Track the owning function for each captured local, update environment access logic to traverse parent chains, and initialize the parent pointer when allocating environments. This enhances support for deeply nested closures and corrects environment memory layout.
Adjusts allocation sizes and field offsets for closure environments in multiple .wat test files, changing from 4 to 8 bytes (and similar increases for larger environments) and updating i32.store/load instructions to use the correct offsets. This aligns the test code with a new closure environment memory layout, likely reflecting changes in the compiler's closure representation.
Updated the NOTICE file to include Anakun <anakun@opnet.org> as a contributor.
Adds logic to properly capture and reference 'this' in closures and methods, ensuring 'this' is stored in the closure environment when needed. Updates compiler and resolver to support lookup and environment slot assignment for captured 'this', improving closure support for methods referencing 'this'.
Removed unnecessary 'self = this' assignments in all closure-returning methods, replacing references to 'self' with 'this'. This simplifies the code and improves readability by leveraging direct 'this' capture in arrow functions.
feat: Add experimental closures support with feature flag
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.
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.
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.
Extended closure variable capture logic in the compiler to handle while, do-while, for, for-of, switch, try/catch/finally, and various expression nodes. Updated test cases to cover closure captures in these new contexts, ensuring correct environment handling and variable scoping for closures in complex control flow and expression scenarios. Found unhandled case of closure with nested arrays.
Replaces all occurrences of the closure environment global variable from '$$~lib/__closure_env' to '$~lib/__closure_env' in the compiler source and test files. This change ensures consistency in global naming and avoids the use of double dollar signs.
Ensure that default values of function parameters are scanned for variable captures before parameter names are added to the inner function scope. This fixes issues where closures in default parameter expressions could not capture outer variables. Adds new tests for closures in default parameter values.
Replaces the collectCapturedNames function with a unified scanNodeForCaptures that supports both local and name modes for closure variable capture analysis. Updates all relevant call sites and improves handling of various node kinds, making closure capture logic more robust and maintainable. Also updates test WAT files to reflect changes in closure environment global naming. Refactor closure function creation logic Removed unused parameters and redundant local set in array rest parameter initialization. Simplified compileClosureFunctionCreation by removing the staticOffset argument, as it is no longer used.
Refactor closure capture analysis and remove collectCapturedNames
5d3a559 to
64e11d9
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes AssemblyScript#302.
Related: AssemblyScript#2956, AssemblyScript#484, AssemblyScript#447.
Changes proposed in this pull request:
⯈ Implemented
throwstatement - Compiles to WebAssembly's nativethrowinstruction using a global$errortag that carries an i32 pointer to Error objects⯈ Implemented
try-catchblocks - Full support for catching exceptions with proper catch variable binding, flow analysis, and nested try-catch structures⯈ Implemented
try-finallyandtry-catch-finally- Complete finally support including the complex case ofreturnstatements inside try/catch blocks, using a pending action pattern to ensure finally always runs before control flow exitsImplementation Details
Exception Tag:
$errorcarrying an i32 pointer to Error objectensureExceptionTag()when first neededThrow Statement (
compileThrowStatement):Feature.ExceptionHandlingis enabled, generatesmodule.throw("$error", [valueExpr])abort()when feature is disabled (preserves existing behavior)FlowFlags.Throws | FlowFlags.Terminateson the flowTry-Catch (
compileTryStatement):try/catchblocks via Binaryenmodule.pop()to retrieve the exception value_BinaryenLocalSetto avoid shadow stack interference with pop placementTry-Finally with Return Support:
Uses a "pending action" pattern to defer returns until after finally executes:
pendingActionLocal(i32): tracks pending action (0=none, 1=return)pendingValueLocal: stores the pending return valueReturn in finally block overrides any pending return from try/catch:
Structure generated:
Core changes in
src/compiler.ts:exceptionTagEnsuredfield andensureExceptionTag()method for lazy tag creationcompileThrowStatement()updated to usemodule.throw()when feature enabledcompileTryStatement()completely rewritten with full try-catch-finally supportcompileReturnStatement()updated to check for try-finally contextSupporting changes in
src/flow.ts:tryFinallyPendingActionLocal- local index for pending action trackingtryFinallyPendingValueLocal- local index for pending return valuetryFinallyDispatchLabel- label to branch to for finally dispatchtryFinallyReturnType- return type for the pending valueisInTryFinallygetter andgetTryFinallyContext()methodTest Coverage
Basic Tests:
testThrow()- Basic throw statementtestTryCatch()- Basic try-catchtestCatchVar()- Accessing caught exception variable (e.message)testNoThrow()- Try-catch when no exception is throwntestFinally()- Basic finally blocktestNested()- Nested try-catch blocksFinally with Return Tests:
testReturnInCatchFinally()- Return in catch with finally (finally must run first)testTryCatchFinally()- Try-catch-finally without return in catchtestFinallyWithException()- Finally runs even when exception propagatestestFinallyNormalCompletion()- Finally with no exceptiontestReturnFromTry()- Return from try block with finallytestMultipleReturnsWithFinally()- Multiple return points with finallyClass-Based Tests:
CustomError- Custom error class extending ErrorResource- Resource management class with dispose patternCalculator- Class with try-catch in methods (divide,safeDivide)Outer/Inner- Nested class exception handlingStateMachine- State machine with exception-based error handlingCounter- Counter class with exception limitComplex Tests:
testArrayWithExceptions()- Array operations with exceptionstestRethrowWithFinally()- Rethrow with finally (verifies finally runs)testDeepNesting()- Deeply nested try-catch-finally tracking execution orderReturn in Finally Tests:
testReturnInFinally()- Return in finally overrides return in trytestReturnInFinallyOverridesCatch()- Return in finally overrides return in catchtestReturnInFinallySuppressesException()- Return in finally suppresses thrown exceptionLimitations
This implementation has one known limitation:
Usage
# Enable exception handling feature asc myfile.ts --enable exception-handling