@@ -1955,7 +1955,7 @@ class jl_codectx_t {
1955
1955
// local var info. globals are not in here.
1956
1956
SmallVector<jl_varinfo_t , 0 > slots;
1957
1957
std::map<int , jl_varinfo_t > phic_slots;
1958
- std::map<int , std::pair< Value*, Value*> > scope_restore ;
1958
+ std::map<int , Value*> scope_tokens ;
1959
1959
SmallVector<jl_cgval_t , 0 > SAvalues;
1960
1960
SmallVector<std::tuple<jl_cgval_t , BasicBlock *, AllocaInst *, PHINode *, SmallVector<PHINode*,0 >, jl_value_t *>, 0 > PhiNodes;
1961
1961
SmallVector<bool , 0 > ssavalue_assigned;
@@ -6573,8 +6573,6 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result)
6573
6573
}
6574
6574
else if (head == jl_leave_sym) {
6575
6575
int hand_n_leave = 0 ;
6576
- Value *scope_to_restore = nullptr ;
6577
- Value *scope_ptr = nullptr ;
6578
6576
for (size_t i = 0 ; i < jl_expr_nargs (ex); ++i) {
6579
6577
jl_value_t *arg = args[i];
6580
6578
if (arg == jl_nothing)
@@ -6584,20 +6582,27 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result)
6584
6582
jl_value_t *enter_stmt = jl_array_ptr_ref (ctx.code , enter_idx);
6585
6583
if (enter_stmt == jl_nothing)
6586
6584
continue ;
6587
- if (ctx.scope_restore .count (enter_idx))
6588
- std::tie (scope_to_restore, scope_ptr) = ctx.scope_restore [enter_idx];
6585
+ if (ctx.scope_tokens .count (enter_idx)) {
6586
+ // TODO: The semantics of `gc_preserve` are not perfect here. An `Expr(:enter, ...)` block may
6587
+ // have multiple exits, but effects of `preserve_end` are only extended to the end of the
6588
+ // dominance of each `Expr(:leave, ...)`.
6589
+ //
6590
+ // That means that a scope object can suddenly end up preserved again outside of an
6591
+ // `Expr(:enter, ...)` region where it ought to be dead. It'd be preferable if the effects
6592
+ // of gc_preserve_end propagated through a control-flow joins as long as all incoming
6593
+ // agree about the preserve state.
6594
+ //
6595
+ // This is correct as-is anyway - it just means the scope lives longer than it needs to
6596
+ // if the `Expr(:enter, ...)` has multiple exits.
6597
+ ctx.builder .CreateCall (prepare_call (gc_preserve_end_func), {ctx.scope_tokens [enter_idx]});
6598
+ }
6589
6599
if (jl_enternode_catch_dest (enter_stmt)) {
6590
6600
// We're not actually setting up the exception frames for these, so
6591
6601
// we don't need to exit them.
6592
6602
hand_n_leave += 1 ;
6593
6603
}
6594
6604
}
6595
6605
ctx.builder .CreateCall (prepare_call (jlleave_noexcept_func), {get_current_task (ctx), ConstantInt::get (getInt32Ty (ctx.builder .getContext ()), hand_n_leave)});
6596
- if (scope_to_restore) {
6597
- jl_aliasinfo_t scope_ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_gcframe );
6598
- scope_ai.decorateInst (
6599
- ctx.builder .CreateAlignedStore (scope_to_restore, scope_ptr, ctx.types ().alignof_ptr ));
6600
- }
6601
6606
}
6602
6607
else if (head == jl_pop_exception_sym) {
6603
6608
jl_cgval_t excstack_state = emit_expr (ctx, jl_exprarg (expr, 0 ));
@@ -7180,7 +7185,7 @@ static Value *get_tls_world_age_field(jl_codectx_t &ctx)
7180
7185
static Value *get_scope_field (jl_codectx_t &ctx)
7181
7186
{
7182
7187
Value *ct = get_current_task (ctx);
7183
- return emit_ptrgep (ctx, ct, offsetof (jl_task_t , scope), " current_scope " );
7188
+ return emit_ptrgep (ctx, ct, offsetof (jl_task_t , scope), " scope " );
7184
7189
}
7185
7190
7186
7191
Function *get_or_emit_fptr1 (StringRef preal_decl, Module *M)
@@ -9604,28 +9609,6 @@ static jl_llvm_functions_t
9604
9609
continue ;
9605
9610
}
9606
9611
else if (jl_is_enternode (stmt)) {
9607
- // For the two-arg version of :enter, twiddle the scope
9608
- Value *scope_ptr = NULL ;
9609
- Value *old_scope = NULL ;
9610
- jl_aliasinfo_t scope_ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_gcframe );
9611
- if (jl_enternode_scope (stmt)) {
9612
- jl_cgval_t new_scope = emit_expr (ctx, jl_enternode_scope (stmt));
9613
- if (new_scope.typ == jl_bottom_type) {
9614
- // Probably dead code, but let's be loud about it in case it isn't, so we fail
9615
- // at the point of the miscompile, rather than later when something attempts to
9616
- // read the scope.
9617
- emit_error (ctx, " (INTERNAL ERROR): Attempted to execute EnterNode with bad scope" );
9618
- find_next_stmt (-1 );
9619
- continue ;
9620
- }
9621
- Value *new_scope_boxed = boxed (ctx, new_scope);
9622
- scope_ptr = get_scope_field (ctx);
9623
- old_scope = scope_ai.decorateInst (
9624
- ctx.builder .CreateAlignedLoad (ctx.types ().T_prjlvalue , scope_ptr, ctx.types ().alignof_ptr ));
9625
- scope_ai.decorateInst (
9626
- ctx.builder .CreateAlignedStore (new_scope_boxed, scope_ptr, ctx.types ().alignof_ptr ));
9627
- ctx.scope_restore [cursor] = std::make_pair (old_scope, scope_ptr);
9628
- }
9629
9612
int lname = jl_enternode_catch_dest (stmt);
9630
9613
if (lname) {
9631
9614
// Save exception stack depth at enter for use in pop_exception
@@ -9651,16 +9634,31 @@ static jl_llvm_functions_t
9651
9634
ctx.builder .SetInsertPoint (catchpop);
9652
9635
{
9653
9636
ctx.builder .CreateCall (prepare_call (jlleave_func), {get_current_task (ctx), ConstantInt::get (getInt32Ty (ctx.builder .getContext ()), 1 )});
9654
- if (old_scope) {
9655
- scope_ai.decorateInst (
9656
- ctx.builder .CreateAlignedStore (old_scope, scope_ptr, ctx.types ().alignof_ptr ));
9657
- }
9658
9637
ctx.builder .CreateBr (handlr);
9659
9638
}
9660
9639
ctx.builder .SetInsertPoint (tryblk);
9661
9640
auto ehptr = emit_ptrgep (ctx, ct, offsetof (jl_task_t , eh));
9662
9641
ctx.builder .CreateAlignedStore (ehbuf, ehptr, ctx.types ().alignof_ptr );
9663
9642
}
9643
+ // For the two-arg version of :enter, twiddle the scope
9644
+ if (jl_enternode_scope (stmt)) {
9645
+ jl_cgval_t scope = emit_expr (ctx, jl_enternode_scope (stmt));
9646
+ if (scope.typ == jl_bottom_type) {
9647
+ // Probably dead code, but let's be loud about it in case it isn't, so we fail
9648
+ // at the point of the miscompile, rather than later when something attempts to
9649
+ // read the scope.
9650
+ emit_error (ctx, " (INTERNAL ERROR): Attempted to execute EnterNode with bad scope" );
9651
+ find_next_stmt (-1 );
9652
+ continue ;
9653
+ }
9654
+ Value *scope_boxed = boxed (ctx, scope);
9655
+ StoreInst *scope_store = ctx.builder .CreateAlignedStore (scope_boxed, get_scope_field (ctx), ctx.types ().alignof_ptr );
9656
+ jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_gcframe ).decorateInst (scope_store);
9657
+ // GC preserve the scope, since it is not rooted in the `jl_handler_t *`
9658
+ // and may be removed from jl_current_task by any nested block and then
9659
+ // replaced later
9660
+ ctx.scope_tokens [cursor] = ctx.builder .CreateCall (prepare_call (gc_preserve_begin_func), {scope_boxed});
9661
+ }
9664
9662
}
9665
9663
else {
9666
9664
emit_stmtpos (ctx, stmt, cursor);
0 commit comments