11use crate :: bytecompiler:: ByteCompiler ;
2- #[ cfg( not( feature = "experimental" ) ) ]
2+ #[ cfg( feature = "experimental" ) ]
3+ use crate :: bytecompiler:: jump_control:: JumpControlInfoFlags ;
34use boa_ast:: statement:: Block ;
45#[ cfg( feature = "experimental" ) ]
56use boa_ast:: {
67 declaration:: LexicalDeclaration ,
78 operations:: { LexicallyScopedDeclaration , lexically_scoped_declarations} ,
8- statement:: Block ,
99} ;
1010
1111impl ByteCompiler < ' _ > {
@@ -30,12 +30,90 @@ impl ByteCompiler<'_> {
3030 } )
3131 . sum ( ) ;
3232
33- self . compile_statement_list ( block. statement_list ( ) , use_expr, true ) ;
34-
35- // Emit DisposeResources with the static count if there are any using declarations
3633 #[ cfg( feature = "experimental" ) ]
37- if using_count > 0 {
38- self . bytecode . emit_dispose_resources ( using_count. into ( ) ) ;
34+ let has_using = using_count > 0 ;
35+
36+ #[ cfg( not( feature = "experimental" ) ) ]
37+ let has_using = false ;
38+
39+ if has_using {
40+ #[ cfg( feature = "experimental" ) ]
41+ {
42+ // Blocks with `using` declarations need try-finally semantics
43+ // Allocate registers for finally control flow (same pattern as try-finally)
44+ let finally_re_throw = self . register_allocator . alloc ( ) ;
45+ let finally_jump_index = self . register_allocator . alloc ( ) ;
46+
47+ self . bytecode . emit_store_true ( finally_re_throw. variable ( ) ) ;
48+ self . bytecode . emit_store_zero ( finally_jump_index. variable ( ) ) ;
49+
50+ // Push jump control info to handle break/continue/return through disposal
51+ self . push_try_with_finally_control_info (
52+ & finally_re_throw,
53+ & finally_jump_index,
54+ use_expr,
55+ ) ;
56+
57+ // Push exception handler to catch any exceptions during block execution
58+ let handler = self . push_handler ( ) ;
59+
60+ // Compile the block body (this includes the `using` declarations)
61+ self . compile_statement_list ( block. statement_list ( ) , use_expr, true ) ;
62+
63+ // Normal exit: mark that we don't need to re-throw
64+ self . bytecode . emit_store_false ( finally_re_throw. variable ( ) ) ;
65+
66+ let finally_jump = self . jump ( ) ;
67+
68+ // Exception path: patch the handler
69+ self . patch_handler ( handler) ;
70+
71+ // Push a second handler for exceptions during exception handling
72+ let catch_handler = self . push_handler ( ) ;
73+ let error = self . register_allocator . alloc ( ) ;
74+ self . bytecode . emit_exception ( error. variable ( ) ) ;
75+ self . bytecode . emit_store_true ( finally_re_throw. variable ( ) ) ;
76+
77+ let no_throw = self . jump ( ) ;
78+ self . patch_handler ( catch_handler) ;
79+
80+ self . patch_jump ( no_throw) ;
81+ self . patch_jump ( finally_jump) ;
82+
83+ // Finally block: dispose resources
84+ let finally_start = self . next_opcode_location ( ) ;
85+ self . jump_info
86+ . last_mut ( )
87+ . expect ( "there should be a jump control info" )
88+ . flags |= JumpControlInfoFlags :: IN_FINALLY ;
89+
90+ // Save accumulator (disposal might modify it, similar to compile_finally_stmt)
91+ let value = self . register_allocator . alloc ( ) ;
92+ self . bytecode
93+ . emit_set_register_from_accumulator ( value. variable ( ) ) ;
94+
95+ // Emit disposal logic
96+ self . bytecode . emit_dispose_resources ( using_count. into ( ) ) ;
97+
98+ // Restore accumulator
99+ self . bytecode . emit_set_accumulator ( value. variable ( ) ) ;
100+ self . register_allocator . dealloc ( value) ;
101+
102+ // Re-throw if there was an exception
103+ let do_not_throw_exit = self . jump_if_false ( & finally_re_throw) ;
104+ self . bytecode . emit_throw ( error. variable ( ) ) ;
105+ self . register_allocator . dealloc ( error) ;
106+ self . patch_jump ( do_not_throw_exit) ;
107+
108+ // Pop jump control info (this handles break/continue/return via jump table)
109+ self . pop_try_with_finally_control_info ( finally_start) ;
110+
111+ self . register_allocator . dealloc ( finally_re_throw) ;
112+ self . register_allocator . dealloc ( finally_jump_index) ;
113+ }
114+ } else {
115+ // Normal block compilation (no using declarations)
116+ self . compile_statement_list ( block. statement_list ( ) , use_expr, true ) ;
39117 }
40118
41119 self . pop_declarative_scope ( scope) ;
0 commit comments