@@ -356,7 +356,8 @@ static GlobalVariable *jlgetworld_global;
356356
357357// placeholder functions
358358static Function *gcroot_flush_func;
359- static Function *gc_use_func;
359+ static Function *gc_preserve_begin_func;
360+ static Function *gc_preserve_end_func;
360361static Function *except_enter_func;
361362static Function *pointer_from_objref_func;
362363
@@ -3905,6 +3906,42 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr)
39053906 else if (head == boundscheck_sym) {
39063907 return mark_julia_const (bounds_check_enabled (ctx, jl_true) ? jl_true : jl_false);
39073908 }
3909+ else if (head == gc_preserve_begin_sym) {
3910+ size_t nargs = jl_array_len (ex->args );
3911+ jl_cgval_t *argv = (jl_cgval_t *)alloca (sizeof (jl_cgval_t ) * nargs);
3912+ for (size_t i = 0 ; i < nargs; ++i) {
3913+ argv[i] = emit_expr (ctx, args[i]);
3914+ }
3915+ size_t nargsboxed = 0 ;
3916+ Value **vals = (Value**)alloca (sizeof (Value *) * nargs);
3917+ for (size_t i = 0 ; i < nargs; ++i) {
3918+ if (!argv[i].isboxed ) {
3919+ // This is intentionally not an error to allow writing
3920+ // generic code more easily.
3921+ continue ;
3922+ } else if (argv[i].constant ) {
3923+ continue ;
3924+ }
3925+ vals[nargsboxed++] = argv[i].Vboxed ;
3926+ }
3927+ Value *token = ctx.builder .CreateCall (prepare_call (gc_preserve_begin_func),
3928+ ArrayRef<Value*>(vals, nargsboxed));
3929+ jl_cgval_t tok (token, NULL , false , (jl_value_t *)jl_void_type, NULL );
3930+ tok.isimmutable = true ;
3931+ return tok;
3932+ }
3933+ else if (head == gc_preserve_end_sym) {
3934+ // We only support ssa values as the argument. Everything else will
3935+ // fall back to the default behavior of preserving the argument value
3936+ // until the end of the scope, which is correct, but not optimal.
3937+ if (!jl_is_ssavalue (args[0 ])) {
3938+ return jl_cgval_t ((jl_value_t *)jl_void_type);
3939+ }
3940+ jl_cgval_t token = emit_expr (ctx, args[0 ]);
3941+ assert (token.V ->getType ()->isTokenTy ());
3942+ ctx.builder .CreateCall (prepare_call (gc_preserve_end_func), {token.V });
3943+ return jl_cgval_t ((jl_value_t *)jl_void_type);
3944+ }
39083945 else {
39093946 if (!strcmp (jl_symbol_name (head), " $" ))
39103947 jl_error (" syntax: prefix \" $\" in non-quoted expression" );
@@ -6526,11 +6563,17 @@ static void init_julia_llvm_env(Module *m)
65266563 " julia.gcroot_flush" );
65276564 add_named_global (gcroot_flush_func, (void *)NULL , /* dllimport*/ false );
65286565
6529- gc_use_func = Function::Create (FunctionType::get (T_void ,
6530- ArrayRef<Type*>(PointerType::get (T_jlvalue, AddressSpace::Derived)), false ),
6566+ gc_preserve_begin_func = Function::Create (FunctionType::get (Type::getTokenTy (jl_LLVMContext) ,
6567+ ArrayRef<Type*>(), true ),
65316568 Function::ExternalLinkage,
6532- " julia.gc_use" );
6533- add_named_global (gc_use_func, (void *)NULL , /* dllimport*/ false );
6569+ " llvm.julia.gc_preserve_begin" );
6570+ add_named_global (gc_preserve_begin_func, (void *)NULL , /* dllimport*/ false );
6571+
6572+ gc_preserve_end_func = Function::Create (FunctionType::get (T_void,
6573+ ArrayRef<Type*>(Type::getTokenTy (jl_LLVMContext)), false ),
6574+ Function::ExternalLinkage,
6575+ " llvm.julia.gc_preserve_end" );
6576+ add_named_global (gc_preserve_end_func, (void *)NULL , /* dllimport*/ false );
65346577
65356578 pointer_from_objref_func = Function::Create (FunctionType::get (T_size,
65366579 ArrayRef<Type*>(PointerType::get (T_jlvalue, AddressSpace::Derived)), false ),
0 commit comments