/home/travis/build/MoarVM/MoarVM/src/core/callsite.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Checks if two callsiates are equal. */ |
4 | | static MVMint32 callsites_equal(MVMThreadContext *tc, MVMCallsite *cs1, MVMCallsite *cs2, |
5 | 1.17M | MVMint32 num_flags, MVMint32 num_nameds) { |
6 | 1.17M | MVMint32 i; |
7 | 1.17M | |
8 | 1.17M | if (num_flags && memcmp(cs1->arg_flags, cs2->arg_flags, num_flags)) |
9 | 1.10M | return 0; |
10 | 1.17M | |
11 | 85.3k | for (i = 0; i < num_nameds; i++) |
12 | 59.1k | if (!MVM_string_equal(tc, cs1->arg_names[i], cs2->arg_names[i])) |
13 | 43.5k | return 0; |
14 | 69.8k | |
15 | 26.2k | return 1; |
16 | 69.8k | } |
17 | | |
18 | | static MVMCallsite null_args_callsite = { NULL, 0, 0, 0, 0, 0, 0, 0 }; |
19 | | |
20 | | static MVMCallsiteEntry obj_arg_flags[] = { MVM_CALLSITE_ARG_OBJ }; |
21 | | static MVMCallsite inv_arg_callsite = { obj_arg_flags, 1, 1, 1, 0, 0, 0, 0 }; |
22 | | |
23 | | static MVMCallsiteEntry two_obj_arg_flags[] = { MVM_CALLSITE_ARG_OBJ, |
24 | | MVM_CALLSITE_ARG_OBJ }; |
25 | | static MVMCallsite two_args_callsite = { two_obj_arg_flags, 2, 2, 2, 0, 0, 0 }; |
26 | | |
27 | | static MVMCallsiteEntry mnfe_flags[] = { MVM_CALLSITE_ARG_OBJ, |
28 | | MVM_CALLSITE_ARG_STR }; |
29 | | static MVMCallsite methnotfound_callsite = { mnfe_flags, 2, 2, 2, 0 }; |
30 | | |
31 | | static MVMCallsiteEntry fm_flags[] = { MVM_CALLSITE_ARG_OBJ, |
32 | | MVM_CALLSITE_ARG_OBJ, |
33 | | MVM_CALLSITE_ARG_STR }; |
34 | | static MVMCallsite findmeth_callsite = { fm_flags, 3, 3, 3, 0 }; |
35 | | |
36 | | static MVMCallsiteEntry tc_flags[] = { MVM_CALLSITE_ARG_OBJ, |
37 | | MVM_CALLSITE_ARG_OBJ, |
38 | | MVM_CALLSITE_ARG_OBJ }; |
39 | | static MVMCallsite typecheck_callsite = { tc_flags, 3, 3, 3, 0 }; |
40 | | |
41 | | static MVMCallsiteEntry obj_int_flags[] = { MVM_CALLSITE_ARG_OBJ, |
42 | | MVM_CALLSITE_ARG_INT }; |
43 | | static MVMCallsite obj_int_callsite = { obj_int_flags, 2, 2, 2, 0, 0, 0 }; |
44 | | |
45 | | static MVMCallsiteEntry obj_num_flags[] = { MVM_CALLSITE_ARG_OBJ, |
46 | | MVM_CALLSITE_ARG_NUM }; |
47 | | static MVMCallsite obj_num_callsite = { obj_num_flags, 2, 2, 2, 0, 0, 0 }; |
48 | | |
49 | | static MVMCallsiteEntry obj_str_flags[] = { MVM_CALLSITE_ARG_OBJ, |
50 | | MVM_CALLSITE_ARG_STR }; |
51 | | static MVMCallsite obj_str_callsite = { obj_str_flags, 2, 2, 2, 0, 0, 0 }; |
52 | | |
53 | | static MVMCallsiteEntry int_int_arg_flags[] = { MVM_CALLSITE_ARG_INT, MVM_CALLSITE_ARG_INT }; |
54 | | static MVMCallsite int_int_arg_callsite = { int_int_arg_flags, 2, 2, 2, 0, 0, 0, 0 }; |
55 | | |
56 | 216k | MVM_PUBLIC MVMCallsite *MVM_callsite_get_common(MVMThreadContext *tc, MVMCommonCallsiteID id) { |
57 | 216k | switch (id) { |
58 | 4.26k | case MVM_CALLSITE_ID_NULL_ARGS: |
59 | 4.26k | return &null_args_callsite; |
60 | 212k | case MVM_CALLSITE_ID_INV_ARG: |
61 | 212k | return &inv_arg_callsite; |
62 | 24 | case MVM_CALLSITE_ID_TWO_OBJ: |
63 | 24 | return &two_args_callsite; |
64 | 0 | case MVM_CALLSITE_ID_METH_NOT_FOUND: |
65 | 0 | return &methnotfound_callsite; |
66 | 6 | case MVM_CALLSITE_ID_FIND_METHOD: |
67 | 6 | return &findmeth_callsite; |
68 | 10 | case MVM_CALLSITE_ID_TYPECHECK: |
69 | 10 | return &typecheck_callsite; |
70 | 0 | case MVM_CALLSITE_ID_OBJ_INT: |
71 | 0 | return &obj_int_callsite; |
72 | 0 | case MVM_CALLSITE_ID_OBJ_NUM: |
73 | 0 | return &obj_num_callsite; |
74 | 0 | case MVM_CALLSITE_ID_OBJ_STR: |
75 | 0 | return &obj_str_callsite; |
76 | 0 | case MVM_CALLSITE_ID_INT_INT: |
77 | 0 | return &int_int_arg_callsite; |
78 | 0 | default: |
79 | 0 | MVM_exception_throw_adhoc(tc, "get_common_callsite: id %d unknown", id); |
80 | 216k | } |
81 | 216k | } |
82 | | |
83 | 0 | int MVM_callsite_is_common(MVMCallsite *cs) { |
84 | 0 | return cs == &null_args_callsite || |
85 | 0 | cs == &inv_arg_callsite || |
86 | 0 | cs == &two_args_callsite || |
87 | 0 | cs == &methnotfound_callsite || |
88 | 0 | cs == &findmeth_callsite || |
89 | 0 | cs == &typecheck_callsite || |
90 | 0 | cs == &obj_int_callsite || |
91 | 0 | cs == &obj_num_callsite || |
92 | 0 | cs == &obj_str_callsite; |
93 | 0 | } |
94 | | |
95 | 0 | void MVM_callsite_destroy(MVMCallsite *cs) { |
96 | 0 | if (cs->flag_count) { |
97 | 0 | MVM_free(cs->arg_flags); |
98 | 0 | } |
99 | 0 |
|
100 | 0 | if (cs->arg_names) { |
101 | 0 | MVM_free(cs->arg_names); |
102 | 0 | } |
103 | 0 |
|
104 | 0 | if (cs->with_invocant) { |
105 | 0 | MVM_callsite_destroy(cs->with_invocant); |
106 | 0 | } |
107 | 0 |
|
108 | 0 | MVM_free(cs); |
109 | 0 | } |
110 | | |
111 | 12 | MVMCallsite *MVM_callsite_copy(MVMThreadContext *tc, const MVMCallsite *cs) { |
112 | 12 | MVMCallsite *copy = MVM_malloc(sizeof(MVMCallsite)); |
113 | 12 | |
114 | 12 | if (cs->flag_count) { |
115 | 12 | copy->arg_flags = MVM_malloc(cs->flag_count); |
116 | 12 | memcpy(copy->arg_flags, cs->arg_flags, cs->flag_count); |
117 | 12 | } |
118 | 12 | |
119 | 12 | if (cs->arg_names) { |
120 | 9 | MVMint32 num_named = MVM_callsite_num_nameds(tc, cs); |
121 | 9 | |
122 | 9 | copy->arg_names = MVM_malloc(num_named * sizeof(MVMString *)); |
123 | 9 | memcpy(copy->arg_names, cs->arg_names, num_named * sizeof(MVMString *)); |
124 | 9 | } |
125 | 3 | else { |
126 | 3 | copy->arg_names = NULL; |
127 | 3 | } |
128 | 12 | |
129 | 12 | if (cs->with_invocant) { |
130 | 0 | copy->with_invocant = MVM_callsite_copy(tc, cs->with_invocant); |
131 | 0 | } |
132 | 12 | else { |
133 | 12 | copy->with_invocant = NULL; |
134 | 12 | } |
135 | 12 | |
136 | 12 | copy->flag_count = cs->flag_count; |
137 | 12 | copy->arg_count = cs->arg_count; |
138 | 12 | copy->num_pos = cs->num_pos; |
139 | 12 | copy->has_flattening = cs->has_flattening; |
140 | 12 | copy->is_interned = cs->is_interned; |
141 | 12 | |
142 | 12 | return copy; |
143 | 12 | } |
144 | | |
145 | 130 | void MVM_callsite_initialize_common(MVMThreadContext *tc) { |
146 | 130 | MVMCallsite *ptr; |
147 | 130 | |
148 | 130 | ptr = &inv_arg_callsite; |
149 | 130 | MVM_callsite_try_intern(tc, &ptr); |
150 | 130 | ptr = &null_args_callsite; |
151 | 130 | MVM_callsite_try_intern(tc, &ptr); |
152 | 130 | ptr = &methnotfound_callsite; |
153 | 130 | MVM_callsite_try_intern(tc, &ptr); |
154 | 130 | ptr = &two_args_callsite; |
155 | 130 | MVM_callsite_try_intern(tc, &ptr); |
156 | 130 | ptr = &findmeth_callsite; |
157 | 130 | MVM_callsite_try_intern(tc, &ptr); |
158 | 130 | ptr = &typecheck_callsite; |
159 | 130 | MVM_callsite_try_intern(tc, &ptr); |
160 | 130 | } |
161 | | |
162 | | /* Tries to intern the callsite, freeing and updating the one passed in and |
163 | | * replacing it with an already interned one if we find it. */ |
164 | 67.9k | MVM_PUBLIC void MVM_callsite_try_intern(MVMThreadContext *tc, MVMCallsite **cs_ptr) { |
165 | 67.9k | MVMCallsiteInterns *interns = tc->instance->callsite_interns; |
166 | 67.9k | MVMCallsite *cs = *cs_ptr; |
167 | 67.9k | MVMint32 num_flags = cs->flag_count; |
168 | 67.9k | MVMint32 num_nameds = MVM_callsite_num_nameds(tc, cs); |
169 | 67.9k | MVMint32 i, found; |
170 | 67.9k | |
171 | 67.9k | /* Can't intern anything with flattening. */ |
172 | 67.9k | if (cs->has_flattening) |
173 | 6.64k | return; |
174 | 67.9k | |
175 | 67.9k | /* Also can't intern past the max arity. */ |
176 | 61.2k | if (num_flags >= MVM_INTERN_ARITY_LIMIT) |
177 | 399 | return; |
178 | 61.2k | |
179 | 61.2k | /* Can intern things with nameds, provided we know the names. */ |
180 | 60.8k | if (num_nameds > 0 && !cs->arg_names) |
181 | 0 | return; |
182 | 60.8k | |
183 | 60.8k | /* Obtain mutex protecting interns store. */ |
184 | 60.8k | uv_mutex_lock(&tc->instance->mutex_callsite_interns); |
185 | 60.8k | |
186 | 60.8k | /* Search for a match. */ |
187 | 60.8k | found = 0; |
188 | 1.20M | for (i = 0; i < interns->num_by_arity[num_flags]; i++) { |
189 | 1.17M | if (callsites_equal(tc, interns->by_arity[num_flags][i], cs, num_flags, num_nameds)) { |
190 | 26.2k | /* Got a match! Free the one we were passed and replace it with |
191 | 26.2k | * the interned one. */ |
192 | 26.2k | if (num_flags) |
193 | 24.6k | MVM_free(cs->arg_flags); |
194 | 26.2k | MVM_free(cs->arg_names); |
195 | 26.2k | MVM_free(cs); |
196 | 26.2k | *cs_ptr = interns->by_arity[num_flags][i]; |
197 | 26.2k | found = 1; |
198 | 26.2k | break; |
199 | 26.2k | } |
200 | 1.17M | } |
201 | 60.8k | |
202 | 60.8k | /* If it wasn't found, store it for the future. */ |
203 | 60.8k | if (!found) { |
204 | 34.6k | if (interns->num_by_arity[num_flags] % 8 == 0) { |
205 | 4.82k | if (interns->num_by_arity[num_flags]) |
206 | 3.78k | interns->by_arity[num_flags] = MVM_realloc( |
207 | 3.78k | interns->by_arity[num_flags], |
208 | 3.78k | sizeof(MVMCallsite *) * (interns->num_by_arity[num_flags] + 8)); |
209 | 4.82k | else |
210 | 1.04k | interns->by_arity[num_flags] = MVM_malloc(sizeof(MVMCallsite *) * 8); |
211 | 4.82k | } |
212 | 34.6k | interns->by_arity[num_flags][interns->num_by_arity[num_flags]++] = cs; |
213 | 34.6k | cs->is_interned = 1; |
214 | 34.6k | } |
215 | 60.8k | |
216 | 60.8k | /* Finally, release mutex. */ |
217 | 60.8k | uv_mutex_unlock(&tc->instance->mutex_callsite_interns); |
218 | 60.8k | } |