-
-
Notifications
You must be signed in to change notification settings - Fork 648
Implement core disposal logic for explicit resource management #5079
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
abhinavs1920
wants to merge
21
commits into
boa-dev:main
Choose a base branch
from
abhinavs1920:feat/res2
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.
Open
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
e47a274
feat: Implement core disposal logic for explicit resource management
abhinavs1920 992583f
Merge branch 'main' into feat/res2
abhinavs1920 81a3f59
fix: opcode enum
abhinavs1920 92b7fa0
fix: formatting and lint issues
abhinavs1920 d3aa12e
Merge branch 'main' into feat/res2
abhinavs1920 201be32
Merge branch 'main' into feat/res2
abhinavs1920 d0517fe
Merge branch 'main' into feat/res2
abhinavs1920 2b99ecd
refactor: encode using declaration count statically in DisposeResourc…
abhinavs1920 42af9af
Merge branch 'main' into feat/res2
abhinavs1920 6935488
Merge branch 'main' into feat/res2
abhinavs1920 af80f7a
fix: restore Reserved1/2/3, remove global opcodes re-added by mistake
abhinavs1920 373889d
feat: gate using declarations behind experimental feature flag
abhinavs1920 a684036
Merge branch 'main' into feat/res2
abhinavs1920 abc7fc7
Merge branch 'main' into feat/res2
abhinavs1920 601309c
Merge branch 'main' into feat/res2
abhinavs1920 2d6f4d9
Merge branch 'main' into feat/res2
abhinavs1920 a438cee
feat: integrate try-finally semantics for using declarations
abhinavs1920 3d22954
fix: wrap function bodies with `using` declarations in try-finally fo…
abhinavs1920 16dbb0d
Merge branch 'main' into feat/res2
abhinavs1920 e3149cb
fix: formatting issue
abhinavs1920 17abdf8
feat: Add SuppressedError builtin
abhinavs1920 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,38 @@ | ||
| use crate::bytecompiler::ByteCompiler; | ||
| use boa_ast::statement::Block; | ||
| use boa_ast::{ | ||
| declaration::LexicalDeclaration, | ||
| operations::{LexicallyScopedDeclaration, lexically_scoped_declarations}, | ||
| statement::Block, | ||
| }; | ||
|
|
||
| impl ByteCompiler<'_> { | ||
| /// Compile a [`Block`] `boa_ast` node | ||
| pub(crate) fn compile_block(&mut self, block: &Block, use_expr: bool) { | ||
| let scope = self.push_declarative_scope(block.scope()); | ||
| self.block_declaration_instantiation(block); | ||
|
|
||
| // Check if this block has any using declarations | ||
| let has_using = lexically_scoped_declarations(block).iter().any(|decl| { | ||
| matches!( | ||
| decl, | ||
| LexicallyScopedDeclaration::LexicalDeclaration( | ||
| LexicalDeclaration::Using(_) | LexicalDeclaration::AwaitUsing(_) | ||
| ) | ||
| ) | ||
| }); | ||
|
|
||
| // Push disposal scope if this block has using declarations | ||
| if has_using { | ||
| self.bytecode.emit_push_disposal_scope(); | ||
| } | ||
|
|
||
| self.compile_statement_list(block.statement_list(), use_expr, true); | ||
|
|
||
| // Dispose resources if this block has using declarations | ||
| if has_using { | ||
| self.bytecode.emit_dispose_resources(); | ||
| } | ||
|
|
||
| self.pop_declarative_scope(scope); | ||
| } | ||
| } |
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| use crate::{ | ||
| Context, JsResult, | ||
| vm::opcode::{Operation, RegisterOperand}, | ||
| }; | ||
|
|
||
| /// `AddDisposableResource` implements the AddDisposableResource operation. | ||
| /// | ||
| /// This opcode adds a resource to the disposal stack for later cleanup. | ||
| /// | ||
| /// Operation: | ||
| /// - Stack: **=>** | ||
| /// - Registers: | ||
| /// - Input: value | ||
| pub(crate) struct AddDisposableResource; | ||
|
|
||
| impl AddDisposableResource { | ||
| pub(crate) fn operation(value: RegisterOperand, context: &mut Context) -> JsResult<()> { | ||
| let value = context.vm.get_register(value.into()).clone(); | ||
|
|
||
| // Per spec: If value is null or undefined, return | ||
| if value.is_null_or_undefined() { | ||
| return Ok(()); | ||
| } | ||
|
|
||
| // Get the dispose method (value[Symbol.dispose]) | ||
| let key = crate::JsSymbol::dispose(); | ||
| let dispose_method = value.get_method(key, context)?; | ||
|
|
||
| // If dispose method is None, return | ||
| let Some(dispose_method) = dispose_method else { | ||
| return Ok(()); | ||
| }; | ||
|
|
||
| // Add to disposal stack | ||
| context | ||
| .vm | ||
| .push_disposable_resource(value, dispose_method.into()); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| impl Operation for AddDisposableResource { | ||
| const NAME: &'static str = "AddDisposableResource"; | ||
| const INSTRUCTION: &'static str = "INST - AddDisposableResource"; | ||
| const COST: u8 = 3; | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| use crate::{Context, JsError, JsNativeError, JsResult, vm::opcode::Operation}; | ||
|
|
||
| /// `DisposeResources` implements the DisposeResources operation. | ||
| /// | ||
| /// This opcode disposes all resources in the current disposal stack. | ||
| /// | ||
| /// Operation: | ||
| /// - Stack: **=>** | ||
| pub(crate) struct DisposeResources; | ||
|
|
||
| impl DisposeResources { | ||
| pub(crate) fn operation((): (), context: &mut Context) -> JsResult<()> { | ||
| let mut suppressed_error: Option<JsError> = None; | ||
|
|
||
| // Get the scope depth to know how many resources to dispose | ||
| let scope_depth = context.vm.current_disposal_scope_depth(); | ||
|
|
||
| // Dispose resources in reverse order (LIFO) until we reach the scope depth | ||
| while context.vm.disposal_stack.len() > scope_depth { | ||
| if let Some((value, method)) = context.vm.pop_disposable_resource() { | ||
| // Call the dispose method | ||
| let result = method.call(&value, &[], context); | ||
|
|
||
| // If an error occurs, aggregate it | ||
| if let Err(err) = result { | ||
| suppressed_error = Some(match suppressed_error { | ||
| None => err, | ||
| Some(previous) => { | ||
| // Create a SuppressedError | ||
| create_suppressed_error(err, &previous, context) | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Pop the disposal scope depth marker | ||
| context.vm.pop_disposal_scope(); | ||
|
|
||
| // If there were any errors, throw the aggregated error | ||
| if let Some(err) = suppressed_error { | ||
| return Err(err); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| impl Operation for DisposeResources { | ||
| const NAME: &'static str = "DisposeResources"; | ||
| const INSTRUCTION: &'static str = "INST - DisposeResources"; | ||
| const COST: u8 = 5; | ||
| } | ||
|
|
||
| /// Helper function to create a SuppressedError | ||
| fn create_suppressed_error( | ||
| _error: JsError, | ||
| suppressed: &JsError, | ||
| _context: &mut Context, | ||
| ) -> JsError { | ||
| // For now, we'll create a simple error that contains both errors | ||
| // TODO: Implement proper SuppressedError builtin in Phase 2 | ||
| let message = format!("An error was suppressed during disposal: {suppressed}"); | ||
|
|
||
| // Attach the original error as a property | ||
| // This is a temporary solution until SuppressedError is implemented | ||
| JsNativeError::error().with_message(message).into() | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| mod add_disposable; | ||
| mod dispose_resources; | ||
| mod push_scope; | ||
|
|
||
| pub(crate) use add_disposable::*; | ||
| pub(crate) use dispose_resources::*; | ||
| pub(crate) use push_scope::*; |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| use crate::{Context, vm::opcode::Operation}; | ||
|
|
||
| /// `PushDisposalScope` marks the current disposal stack depth for a new scope. | ||
| /// | ||
| /// This opcode is emitted at the beginning of blocks that contain `using` declarations. | ||
| /// | ||
| /// Operation: | ||
| /// - Stack: **=>** | ||
| pub(crate) struct PushDisposalScope; | ||
|
|
||
| impl PushDisposalScope { | ||
| pub(crate) fn operation((): (), context: &mut Context) { | ||
| context.vm.push_disposal_scope(); | ||
| } | ||
| } | ||
|
|
||
| impl Operation for PushDisposalScope { | ||
| const NAME: &'static str = "PushDisposalScope"; | ||
| const INSTRUCTION: &'static str = "INST - PushDisposalScope"; | ||
| const COST: u8 = 1; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.