Repository: JuliaLang/julia
File: src/codegen.cpp (C++)

Code before:
                //       of gc_preserve_end propagated through a control-flow joins as long as all incoming
                //       agree about the preserve state.
                //
                //       This is correct as-is anyway - it just means the scope lives longer than it needs to
                //       if the `Expr(:enter, ...)` has multiple exits.
                std::tie(token, scope_to_restore) = ctx.scope_restore[enter_idx];
                ctx.builder.CreateCall(prepare_call(gc_preserve_end_func), {token});
            }
            if (jl_enternode_catch_dest(enter_stmt)) {
                handler_to_end.push_back(ctx.eh_buffers[enter_stmt]);
                // We're not actually setting up the exception frames for these, so
                // we don't need to exit them.
                scope_to_restore = nullptr; // restored by exception handler
            }
        }
        ctx.builder.CreateCall(prepare_call(jlleave_noexcept_func), {get_current_task(ctx), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), handler_to_end.size())});
        auto *handler_sz64 = ConstantInt::get(Type::getInt64Ty(ctx.builder.getContext()),
                  sizeof(jl_handler_t));
        for (AllocaInst *handler : handler_to_end) {
            ctx.builder.CreateLifetimeEnd(handler, handler_sz64);
        }
        if (scope_to_restore) {
            Value *scope_ptr = get_scope_field(ctx);
            jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(
                ctx.builder.CreateAlignedStore(scope_to_restore, scope_ptr, ctx.types().alignof_ptr));
            emit_write_barrier(ctx, get_current_task(ctx), scope_to_restore);
        }
    }
    else if (head == jl_pop_exception_sym) {
        jl_cgval_t excstack_state = emit_expr(ctx, jl_exprarg(expr, 0));
        assert(excstack_state.V && excstack_state.V->getType() == ctx.types().T_size);
        ctx.builder.CreateCall(prepare_call(jl_restore_excstack_func), {get_current_task(ctx), excstack_state.V});
        return;
    }
    else {
        assert(ssaval_result != -1);
        emit_ssaval_assign(ctx, ssaval_result, expr);
    }
}

static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_method_t *closure_method, jl_tupletype_t *env_t, jl_tupletype_t *argt_typ, jl_value_t *rettype)
{
    jl_svec_t *sig_args = NULL;
    jl_value_t *sigtype = NULL;
    JL_GC_PUSH2(&sig_args, &sigtype);

    size_t nsig = 1 + jl_svec_len(argt_typ->parameters);
    sig_args = jl_alloc_svec_uninit(nsig);
    jl_svecset(sig_args, 0, env_t);
    for (size_t i = 0; i < jl_svec_len(argt_typ->parameters); ++i) {
        jl_svecset(sig_args, 1+i, jl_svecref(argt_typ->parameters, i));

Review comment (suggestion):
NAK on this, should be a comment to explain why it is unnecessary or a no-op `emit_self_task_wb` (like we have for the other cases where wbs are omitted as an optimization).

Code after:
                //       of gc_preserve_end propagated through a control-flow joins as long as all incoming
                //       agree about the preserve state.
                //
                //       This is correct as-is anyway - it just means the scope lives longer than it needs to
                //       if the `Expr(:enter, ...)` has multiple exits.
                std::tie(token, scope_to_restore) = ctx.scope_restore[enter_idx];
                ctx.builder.CreateCall(prepare_call(gc_preserve_end_func), {token});
            }
            if (jl_enternode_catch_dest(enter_stmt)) {
                handler_to_end.push_back(ctx.eh_buffers[enter_stmt]);
                // We're not actually setting up the exception frames for these, so
                // we don't need to exit them.
                scope_to_restore = nullptr; // restored by exception handler
            }
        }
        ctx.builder.CreateCall(prepare_call(jlleave_noexcept_func), {get_current_task(ctx), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), handler_to_end.size())});
        auto *handler_sz64 = ConstantInt::get(Type::getInt64Ty(ctx.builder.getContext()),
                  sizeof(jl_handler_t));
        for (AllocaInst *handler : handler_to_end) {
            ctx.builder.CreateLifetimeEnd(handler, handler_sz64);
        }
        if (scope_to_restore) {
            Value *scope_ptr = get_scope_field(ctx);
            jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(
                ctx.builder.CreateAlignedStore(scope_to_restore, scope_ptr, ctx.types().alignof_ptr));
            // NOTE: wb not needed here, due to store to current_task (see jl_gc_wb_current_task)
        }
    }
    else if (head == jl_pop_exception_sym) {
        jl_cgval_t excstack_state = emit_expr(ctx, jl_exprarg(expr, 0));
        assert(excstack_state.V && excstack_state.V->getType() == ctx.types().T_size);
        ctx.builder.CreateCall(prepare_call(jl_restore_excstack_func), {get_current_task(ctx), excstack_state.V});
        return;
    }
    else {
        assert(ssaval_result != -1);
        emit_ssaval_assign(ctx, ssaval_result, expr);
    }
}

static std::pair<Function*, Function*> get_oc_function(jl_codectx_t &ctx, jl_method_t *closure_method, jl_tupletype_t *env_t, jl_tupletype_t *argt_typ, jl_value_t *rettype)
{
    jl_svec_t *sig_args = NULL;
    jl_value_t *sigtype = NULL;
    JL_GC_PUSH2(&sig_args, &sigtype);

    size_t nsig = 1 + jl_svec_len(argt_typ->parameters);
    sig_args = jl_alloc_svec_uninit(nsig);
    jl_svecset(sig_args, 0, env_t);
    for (size_t i = 0; i < jl_svec_len(argt_typ->parameters); ++i) {
        jl_svecset(sig_args, 1+i, jl_svecref(argt_typ->parameters, i));