@@ -862,6 +862,8 @@ static const std::map<jl_fptr_args_t, JuliaFunction*> builtin_func_map = {
862862 { &jl_f_apply_type, new JuliaFunction{" jl_f_apply_type" , get_func_sig, get_func_attrs} },
863863};
864864
865+ static const auto jl_new_opaque_closure_jlcall_func = new JuliaFunction{" jl_new_opaque_closure_jlcall" , get_func_sig, get_func_attrs};
866+
865867static int globalUnique = 0 ;
866868
867869// --- code generation ---
@@ -2624,6 +2626,13 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva
26242626 return emit_box_compare (ctx, arg1, arg2, nullcheck1, nullcheck2);
26252627}
26262628
2629+ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t >
2630+ emit_function (
2631+ jl_method_instance_t *lam,
2632+ jl_code_info_t *src,
2633+ jl_value_t *jlrettype,
2634+ jl_codegen_params_t ¶ms);
2635+
26272636static bool emit_builtin_call (jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
26282637 const jl_cgval_t *argv, size_t nargs, jl_value_t *rt,
26292638 jl_expr_t *ex)
@@ -3228,6 +3237,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
32283237 }
32293238 return true ;
32303239 }
3240+
32313241 return false ;
32323242}
32333243
@@ -4477,6 +4487,98 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
44774487 // it to the inferred type.
44784488 return mark_julia_type (ctx, val, true , (jl_value_t *)jl_any_type);
44794489 }
4490+ else if (head == new_opaque_closure_sym) {
4491+ size_t nargs = jl_array_len (ex->args );
4492+ assert (nargs >= 4 && " Not enough arguments in new_opaque_closure" );
4493+ jl_cgval_t *argv = (jl_cgval_t *)alloca (sizeof (jl_cgval_t ) * nargs);
4494+ for (size_t i = 0 ; i < nargs; ++i) {
4495+ argv[i] = emit_expr (ctx, args[i]);
4496+ }
4497+ const jl_cgval_t &argt = argv[0 ];
4498+ const jl_cgval_t &lb = argv[1 ];
4499+ const jl_cgval_t &ub = argv[2 ];
4500+ const jl_cgval_t &source = argv[3 ];
4501+ if (source.constant == NULL || argt.constant == NULL || lb.constant == NULL || ub.constant == NULL ) {
4502+ // For now, we require non-constant source to be created using
4503+ // eval - we may lift this restriction if necessary.
4504+ emit_error (ctx, " Opaque closure source be constant" );
4505+ return jl_cgval_t ();
4506+ }
4507+ bool valid = jl_is_type (argt.constant ) && jl_is_type (lb.constant ) &&
4508+ jl_is_type (ub.constant );
4509+ if (valid && jl_is_code_info (source.constant ) && jl_is_concrete_immutable (argt.constant )) {
4510+ // TODO: Emit this inline and outline it late using LLVM's coroutine
4511+ // support.
4512+ jl_code_info_t *closure_src = (jl_code_info_t *)source.constant ;
4513+ std::unique_ptr<Module> closure_m;
4514+ jl_llvm_functions_t closure_decls;
4515+
4516+ jl_method_instance_t *li;
4517+ jl_value_t *closure_t ;
4518+ jl_tupletype_t *env_t ;
4519+ jl_svec_t *sig_args;
4520+ JL_GC_PUSH4 (&li, &closure_t , &env_t , &sig_args);
4521+
4522+ li = jl_new_method_instance_uninit ();
4523+ li->uninferred = (jl_value_t *)closure_src;
4524+ jl_tupletype_t *argt_typ = (jl_tupletype_t *)argt.constant ;
4525+
4526+ closure_t = jl_apply_type2 ((jl_value_t *)jl_opaque_closure_type, (jl_value_t *)argt_typ, ub.constant );
4527+
4528+ size_t nsig = 1 + jl_svec_len (argt_typ->parameters );
4529+ sig_args = jl_alloc_svec_uninit (nsig);
4530+ jl_svecset (sig_args, 0 , closure_t );
4531+ for (size_t i = 0 ; i < jl_svec_len (argt_typ->parameters ); ++i) {
4532+ jl_svecset (sig_args, 1 +i, jl_svecref (argt_typ->parameters , i));
4533+ }
4534+ li->specTypes = (jl_value_t *)jl_apply_tuple_type_v (jl_svec_data (sig_args), nsig);
4535+ li->def .module = ctx.module ;
4536+ std::tie (closure_m, closure_decls) = emit_function (li, closure_src,
4537+ ub.constant , ctx.emission_context );
4538+ jl_merge_module (ctx.f ->getParent (), std::move (closure_m));
4539+
4540+ jl_value_t **env_component_ts = (jl_value_t **)alloca (sizeof (jl_value_t *) * (nargs-4 ));
4541+ for (size_t i = 0 ; i < nargs - 4 ; ++i) {
4542+ env_component_ts[i] = argv[4 +i].typ ;
4543+ }
4544+
4545+ env_t = jl_apply_tuple_type_v (env_component_ts, nargs-4 );
4546+
4547+ // TODO: Inline the env at the end of the opaque closure and generate a descriptor for GC
4548+ jl_cgval_t env = emit_new_struct (ctx, (jl_value_t *)env_t , nargs-4 , &argv[4 ]);
4549+
4550+ Function *specptr = ctx.f ->getParent ()->getFunction (closure_decls.specFunctionObject );
4551+ jl_cgval_t fptr = mark_julia_type (ctx,
4552+ specptr ? (llvm::Value*)specptr : (llvm::Value*)ConstantPointerNull::get ((llvm::PointerType*)T_pvoidfunc),
4553+ false , jl_voidpointer_type);
4554+
4555+ Value *jlptr;
4556+ if (closure_decls.functionObject == " jl_fptr_args" ||
4557+ closure_decls.functionObject == " jl_fptr_sparam" ) {
4558+ jlptr = specptr;
4559+ } else {
4560+ jlptr = ctx.f ->getParent ()->getFunction (closure_decls.functionObject );
4561+ }
4562+ jl_cgval_t jlcall_ptr = mark_julia_type (ctx,
4563+ jlptr ? (llvm::Value*)jlptr : (llvm::Value*)ConstantPointerNull::get ((llvm::PointerType*)T_pvoidfunc),
4564+ false , jl_voidpointer_type);
4565+
4566+ jl_cgval_t closure_fields[4 ] = {
4567+ env,
4568+ source,
4569+ jlcall_ptr,
4570+ fptr
4571+ };
4572+
4573+ jl_cgval_t ret = emit_new_struct (ctx, closure_t , 4 , closure_fields);
4574+ JL_GC_POP ();
4575+ return ret;
4576+ }
4577+
4578+ return mark_julia_type (ctx,
4579+ emit_jlcall (ctx, jl_new_opaque_closure_jlcall_func, V_rnull, argv, nargs, JLCALL_F_CC),
4580+ true , jl_any_type);
4581+ }
44804582 else if (head == exc_sym) {
44814583 return mark_julia_type (ctx,
44824584 ctx.builder .CreateCall (prepare_call (jl_current_exception_func)),
@@ -5742,15 +5844,29 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
57425844 ctx.code = src->code ;
57435845
57445846 std::map<int , BasicBlock*> labels;
5847+ bool toplevel = false ;
57455848 ctx.module = jl_is_method (lam->def .method ) ? lam->def .method ->module : lam->def .module ;
57465849 ctx.linfo = lam;
5850+ ctx.name = name_from_method_instance (lam);
5851+ bool is_opaque_closure = false ;
5852+ if (jl_is_method (lam->def .method )) {
5853+ ctx.nargs = lam->def .method ->nargs ;
5854+ }
5855+ else {
5856+ ctx.nargs = 0 ;
5857+ // This is an opaque closure
5858+ jl_datatype_t *closure = jl_first_argument_datatype (lam->specTypes );
5859+ if (closure && jl_is_opaque_closure_type (closure)) {
5860+ assert (jl_is_concrete_immutable (jl_tparam0 (closure)));
5861+ ctx.nargs = 1 + jl_datatype_nfields (jl_tparam0 (closure));
5862+ is_opaque_closure = true ;
5863+ }
5864+ }
5865+ toplevel = !jl_is_method (lam->def .method );
57475866 ctx.rettype = jlrettype;
57485867 ctx.source = src;
5749- ctx.name = name_from_method_instance (lam);
57505868 ctx.funcName = ctx.name ;
57515869 ctx.spvals_ptr = NULL ;
5752- ctx.nargs = jl_is_method (lam->def .method ) ? lam->def .method ->nargs : 0 ;
5753- bool toplevel = !jl_is_method (lam->def .method );
57545870 jl_array_t *stmts = ctx.code ;
57555871 size_t stmtslen = jl_array_dim0 (stmts);
57565872
@@ -5764,7 +5880,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
57645880
57655881 StringRef dbgFuncName = ctx.name ;
57665882 int toplineno = -1 ;
5767- if (jl_is_method (lam->def .method )) {
5883+ if (lam && jl_is_method (lam->def .method )) {
57685884 toplineno = lam->def .method ->line ;
57695885 ctx.file = jl_symbol_name (lam->def .method ->file );
57705886 }
@@ -5793,7 +5909,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
57935909
57945910 assert (lam->specTypes ); // the specTypes field should always be assigned
57955911
5796- if (nreq > 0 && lam->def .method ->isva ) {
5912+ if (nreq > 0 && jl_is_method (lam-> def . value ) && lam->def .method ->isva ) {
57975913 nreq--;
57985914 va = 1 ;
57995915 jl_sym_t *vn = (jl_sym_t *)jl_array_ptr_ref (src->slotnames , ctx.nargs - 1 );
@@ -5820,6 +5936,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
58205936 if (argname == unused_sym)
58215937 continue ;
58225938 jl_value_t *ty = jl_nth_slot_type (lam->specTypes , i);
5939+ // OpaqueClosure implicitly loads the env
5940+ if (i == 0 && is_opaque_closure) {
5941+ if (jl_is_array (src->slottypes )) {
5942+ ty = jl_arrayref ((jl_array_t *)src->slottypes , i);
5943+ }
5944+ else {
5945+ ty = (jl_value_t *)jl_any_type;
5946+ }
5947+ }
58235948 varinfo.value = mark_julia_type (ctx, (Value*)NULL , false , ty);
58245949 }
58255950 if (va && ctx.vaSlot != -1 ) {
@@ -6302,6 +6427,13 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
63026427 }
63036428 }
63046429
6430+ // If this is an opaque closure, implicitly load the env
6431+ if (i == 0 && is_opaque_closure) {
6432+ theArg = convert_julia_type (ctx,
6433+ emit_getfield_knownidx (ctx, theArg, 0 , (jl_datatype_t *)argType),
6434+ vi.value .typ );
6435+ }
6436+
63056437 if (vi.boxroot == NULL ) {
63066438 assert (vi.value .V == NULL && " unexpected variable slot created for argument" );
63076439 // keep track of original (possibly boxed) value to avoid re-boxing or moving
0 commit comments