Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : #include "julia.h"
4 : : #include "julia_internal.h"
5 : :
6 : 8 : jl_value_t *jl_fptr_const_opaque_closure(jl_opaque_closure_t *oc, jl_value_t **args, size_t nargs)
7 : : {
8 : 8 : return oc->captures;
9 : : }
10 : :
11 : : // determine whether `argt` is a valid argument type tuple for the given opaque closure method
12 : 19 : JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *source)
13 : : {
14 [ + + ]: 19 : if (!source->isva) {
15 [ - + ]: 18 : if (jl_is_va_tuple(argt))
16 : 0 : return 0;
17 [ - + ]: 18 : if (jl_nparams(argt)+1 > source->nargs)
18 : 0 : return 0;
19 : : }
20 [ - + ]: 19 : if (jl_nparams(argt) + 1 - jl_is_va_tuple(argt) < source->nargs - source->isva)
21 : 0 : return 0;
22 : 19 : return 1;
23 : : }
24 : :
25 : 52 : static jl_value_t *prepend_type(jl_value_t *t0, jl_tupletype_t *t)
26 : : {
27 : 52 : jl_svec_t *sig_args = NULL;
28 : 52 : JL_GC_PUSH1(&sig_args);
29 : 52 : size_t nsig = 1 + jl_svec_len(t->parameters);
30 : 52 : sig_args = jl_alloc_svec_uninit(nsig);
31 : 52 : jl_svecset(sig_args, 0, t0);
32 [ + + ]: 115 : for (size_t i = 0; i < nsig-1; ++i) {
33 : 63 : jl_svecset(sig_args, 1+i, jl_tparam(t, i));
34 : : }
35 : 52 : jl_value_t *sigtype = (jl_value_t*)jl_apply_tuple_type_v(jl_svec_data(sig_args), nsig);
36 : 52 : JL_GC_POP();
37 : 52 : return sigtype;
38 : : }
39 : :
40 : 48 : static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub,
41 : : jl_value_t *source_, jl_value_t *captures)
42 : : {
43 [ - + ]: 48 : if (!jl_is_tuple_type((jl_value_t*)argt)) {
44 : 0 : jl_error("OpaqueClosure argument tuple must be a tuple type");
45 : : }
46 [ - + ]: 48 : JL_TYPECHK(new_opaque_closure, type, rt_lb);
47 [ - + ]: 48 : JL_TYPECHK(new_opaque_closure, type, rt_ub);
48 [ - + ]: 48 : JL_TYPECHK(new_opaque_closure, method, source_);
49 : 48 : jl_method_t *source = (jl_method_t*)source_;
50 [ + + ]: 48 : if (!source->isva) {
51 [ + + ]: 32 : if (jl_is_va_tuple(argt))
52 : 2 : jl_error("Argument type tuple is vararg but method is not");
53 [ + + ]: 30 : if (jl_nparams(argt)+1 > source->nargs)
54 : 1 : jl_error("Argument type tuple has too many required arguments for method");
55 : : }
56 [ + + ]: 45 : if (jl_nparams(argt) + 1 - jl_is_va_tuple(argt) < source->nargs - source->isva)
57 : 3 : jl_error("Argument type tuple has too few required arguments for method");
58 : 42 : jl_value_t *sigtype = NULL;
59 : 42 : JL_GC_PUSH1(&sigtype);
60 : 42 : sigtype = prepend_type(jl_typeof(captures), argt);
61 : :
62 : : jl_value_t *oc_type JL_ALWAYS_LEAFTYPE;
63 : 42 : oc_type = jl_apply_type2((jl_value_t*)jl_opaque_closure_type, (jl_value_t*)argt, rt_ub);
64 : : JL_GC_PROMISE_ROOTED(oc_type);
65 : :
66 : 42 : jl_method_instance_t *mi = jl_specializations_get_linfo(source, sigtype, jl_emptysvec);
67 : 42 : size_t world = jl_atomic_load_acquire(&jl_world_counter);
68 : 42 : jl_code_instance_t *ci = jl_compile_method_internal(mi, world);
69 : :
70 : 42 : jl_task_t *ct = jl_current_task;
71 : 42 : jl_opaque_closure_t *oc = (jl_opaque_closure_t*)jl_gc_alloc(ct->ptls, sizeof(jl_opaque_closure_t), oc_type);
72 : 42 : JL_GC_POP();
73 : 42 : oc->source = source;
74 : 42 : oc->captures = captures;
75 : 42 : oc->specptr = NULL;
76 [ - + ]: 42 : if (jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_interpret_call) {
77 : 0 : oc->invoke = (jl_fptr_args_t)jl_interpret_opaque_closure;
78 : : }
79 [ + + ]: 42 : else if (jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_args) {
80 : 6 : oc->invoke = jl_atomic_load_relaxed(&ci->specptr.fptr1);
81 : : }
82 [ + + ]: 36 : else if (jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) {
83 : 14 : oc->invoke = (jl_fptr_args_t)jl_fptr_const_opaque_closure;
84 : 14 : oc->captures = ci->rettype_const;
85 : : }
86 : : else {
87 : 22 : oc->invoke = (jl_fptr_args_t)jl_atomic_load_relaxed(&ci->invoke);
88 : : }
89 : 42 : oc->world = world;
90 : 42 : return oc;
91 : : }
92 : :
93 : 38 : jl_opaque_closure_t *jl_new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub,
94 : : jl_value_t *source_, jl_value_t **env, size_t nenv)
95 : : {
96 : 38 : jl_value_t *captures = jl_f_tuple(NULL, env, nenv);
97 : 38 : JL_GC_PUSH1(&captures);
98 : 38 : jl_opaque_closure_t *oc = new_opaque_closure(argt, rt_lb, rt_ub, source_, captures);
99 : 32 : JL_GC_POP();
100 : 32 : return oc;
101 : : }
102 : :
103 : : jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name,
104 : : int nargs, jl_value_t *functionloc, jl_code_info_t *ci, int isva);
105 : :
106 : : JL_DLLEXPORT jl_code_instance_t* jl_new_codeinst(
107 : : jl_method_instance_t *mi, jl_value_t *rettype,
108 : : jl_value_t *inferred_const, jl_value_t *inferred,
109 : : int32_t const_flags, size_t min_world, size_t max_world,
110 : : uint32_t ipo_effects, uint32_t effects, jl_value_t *argescapes,
111 : : uint8_t relocatability);
112 : :
113 : : JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT,
114 : : jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED);
115 : :
116 : 10 : JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info(jl_tupletype_t *argt, jl_value_t *rt_lb, jl_value_t *rt_ub,
117 : : jl_module_t *mod, jl_code_info_t *ci, int lineno, jl_value_t *file, int nargs, int isva, jl_value_t *env)
118 : : {
119 [ - + ]: 10 : if (!ci->inferred)
120 : 0 : jl_error("CodeInfo must already be inferred");
121 : 10 : jl_value_t *root = NULL, *sigtype = NULL;
122 : 10 : jl_code_instance_t *inst = NULL;
123 : 10 : JL_GC_PUSH3(&root, &sigtype, &inst);
124 : 10 : root = jl_box_long(lineno);
125 : 10 : root = jl_new_struct(jl_linenumbernode_type, root, file);
126 : 10 : root = (jl_value_t*)jl_make_opaque_closure_method(mod, jl_nothing, nargs, root, ci, isva);
127 : :
128 : 10 : sigtype = prepend_type(jl_typeof(env), argt);
129 : 10 : jl_method_instance_t *mi = jl_specializations_get_linfo((jl_method_t*)root, sigtype, jl_emptysvec);
130 : 20 : inst = jl_new_codeinst(mi, rt_ub, NULL, (jl_value_t*)ci,
131 : 10 : 0, ((jl_method_t*)root)->primary_world, -1, 0, 0, jl_nothing, 0);
132 : 10 : jl_mi_cache_insert(mi, inst);
133 : :
134 : 10 : jl_opaque_closure_t *oc = new_opaque_closure(argt, rt_lb, rt_ub, root, env);
135 : 10 : JL_GC_POP();
136 : 10 : return oc;
137 : : }
138 : :
139 : 20 : JL_CALLABLE(jl_new_opaque_closure_jlcall)
140 : : {
141 [ - + ]: 20 : if (nargs < 4)
142 : 0 : jl_error("new_opaque_closure: Not enough arguments");
143 : 40 : return (jl_value_t*)jl_new_opaque_closure((jl_tupletype_t*)args[0],
144 : 20 : args[1], args[2], args[3], &args[4], nargs-4);
145 : : }
146 : :
147 : :
148 : : // check whether the specified number of arguments is compatible with the
149 : : // specified number of parameters of the tuple type
150 : 42 : STATIC_INLINE int jl_tupletype_length_compat(jl_value_t *v, size_t nargs) JL_NOTSAFEPOINT
151 : : {
152 : 42 : v = jl_unwrap_unionall(v);
153 [ - + ]: 42 : assert(jl_is_tuple_type(v));
154 : 42 : size_t nparams = jl_nparams(v);
155 [ + + ]: 42 : if (nparams == 0)
156 : 17 : return nargs == 0;
157 : 25 : jl_value_t *va = jl_tparam(v,nparams-1);
158 [ + + ]: 25 : if (jl_is_vararg(va)) {
159 : 6 : jl_value_t *len = jl_unwrap_vararg_num(va);
160 [ - + - - ]: 6 : if (len &&jl_is_long(len))
161 : 0 : return nargs == nparams - 1 + jl_unbox_long(len);
162 : 6 : return nargs >= nparams - 1;
163 : : }
164 : 19 : return nparams == nargs;
165 : : }
166 : :
167 : 42 : JL_CALLABLE(jl_f_opaque_closure_call)
168 : : {
169 : 42 : jl_opaque_closure_t* oc = (jl_opaque_closure_t*)F;
170 : 42 : jl_value_t *argt = jl_tparam0(jl_typeof(oc));
171 [ + + ]: 42 : if (!jl_tupletype_length_compat(argt, nargs))
172 : 4 : jl_method_error(F, args, nargs + 1, oc->world);
173 : 38 : argt = jl_unwrap_unionall(argt);
174 [ - + ]: 38 : assert(jl_is_datatype(argt));
175 [ + - ]: 38 : jl_svec_t *types = jl_get_fieldtypes((jl_datatype_t*)argt);
176 : 38 : size_t ntypes = jl_svec_len(types);
177 [ + + ]: 74 : for (int i = 0; i < nargs; ++i) {
178 [ + + ]: 38 : jl_value_t *typ = i >= ntypes ? jl_svecref(types, ntypes-1) : jl_svecref(types, i);
179 [ + + ]: 38 : if (jl_is_vararg(typ))
180 : 12 : typ = jl_unwrap_vararg(typ);
181 : 38 : jl_typeassert(args[i], typ);
182 : : }
183 : 36 : return oc->invoke(F, args, nargs);
184 : : }
|