Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014 Damien P. George
7 : : * Copyright (c) 2014 Paul Sokolovsky
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include <stdbool.h>
29 : : #include <string.h>
30 : : #include <assert.h>
31 : :
32 : : #include "py/bc0.h"
33 : : #include "py/bc.h"
34 : : #include "py/objfun.h"
35 : :
36 : : #if MICROPY_DEBUG_VERBOSE // print debugging info
37 : : #define DEBUG_PRINT (1)
38 : : #else // don't print debugging info
39 : : #define DEBUG_PRINT (0)
40 : : #define DEBUG_printf(...) (void)0
41 : : #endif
42 : :
43 : 798916 : void mp_encode_uint(void *env, mp_encode_uint_allocator_t allocator, mp_uint_t val) {
44 : : // We store each 7 bits in a separate byte, and that's how many bytes needed
45 : 798916 : byte buf[MP_ENCODE_UINT_MAX_BYTES];
46 : 798916 : byte *p = buf + sizeof(buf);
47 : : // We encode in little-ending order, but store in big-endian, to help decoding
48 : 800854 : do {
49 : 800854 : *--p = val & 0x7f;
50 : 800854 : val >>= 7;
51 [ + + ]: 800854 : } while (val != 0);
52 : 798916 : byte *c = allocator(env, buf + sizeof(buf) - p);
53 [ + + ]: 798918 : if (c != NULL) {
54 [ + + ]: 786074 : while (p != buf + sizeof(buf) - 1) {
55 : 1938 : *c++ = *p++ | 0x80;
56 : : }
57 : 784136 : *c = *p;
58 : : }
59 : 798918 : }
60 : :
61 : 161605 : mp_uint_t mp_decode_uint(const byte **ptr) {
62 : 161605 : mp_uint_t unum = 0;
63 : 161605 : byte val;
64 : 161605 : const byte *p = *ptr;
65 : 161605 : do {
66 : 161605 : val = *p++;
67 : 161605 : unum = (unum << 7) | (val & 0x7f);
68 [ - + ]: 161605 : } while ((val & 0x80) != 0);
69 : 161605 : *ptr = p;
70 : 161605 : return unum;
71 : : }
72 : :
73 : : // This function is used to help reduce stack usage at the caller, for the case when
74 : : // the caller doesn't need to increase the ptr argument. If ptr is a local variable
75 : : // and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler
76 : : // must allocate a slot on the stack for ptr, and this slot cannot be reused for
77 : : // anything else in the function because the pointer may have been stored in a global
78 : : // and reused later in the function.
79 : 159478 : mp_uint_t mp_decode_uint_value(const byte *ptr) {
80 : 159478 : return mp_decode_uint(&ptr);
81 : : }
82 : :
83 : : // This function is used to help reduce stack usage at the caller, for the case when
84 : : // the caller doesn't need the actual value and just wants to skip over it.
85 : 311869 : const byte *mp_decode_uint_skip(const byte *ptr) {
86 : 311869 : while ((*ptr++) & 0x80) {
87 [ - + ]: 311869 : }
88 : 311869 : return ptr;
89 : : }
90 : :
91 : 12 : static NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
92 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
93 : : // generic message, used also for other argument issues
94 : : (void)f;
95 : : (void)expected;
96 : : (void)given;
97 : : mp_arg_error_terse_mismatch();
98 : : #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
99 : : (void)f;
100 : : mp_raise_msg_varg(&mp_type_TypeError,
101 : : MP_ERROR_TEXT("function takes %d positional arguments but %d were given"), expected, given);
102 : : #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
103 : 12 : mp_raise_msg_varg(&mp_type_TypeError,
104 : 12 : MP_ERROR_TEXT("%q() takes %d positional arguments but %d were given"),
105 : : mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given);
106 : : #endif
107 : : }
108 : :
109 : : #if DEBUG_PRINT
110 : : static void dump_args(const mp_obj_t *a, size_t sz) {
111 : : DEBUG_printf("%p: ", a);
112 : : for (size_t i = 0; i < sz; i++) {
113 : : DEBUG_printf("%p ", a[i]);
114 : : }
115 : : DEBUG_printf("\n");
116 : : }
117 : : #else
118 : : #define dump_args(...) (void)0
119 : : #endif
120 : :
121 : : // On entry code_state should be allocated somewhere (stack/heap) and
122 : : // contain the following valid entries:
123 : : // - code_state->fun_bc should contain a pointer to the function object
124 : : // - code_state->ip should contain a pointer to the beginning of the prelude
125 : : // - code_state->sp should be: &code_state->state[0] - 1
126 : : // - code_state->n_state should be the number of objects in the local state
127 : 9088264 : static void mp_setup_code_state_helper(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
128 : : // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
129 : : // usage for the common case of positional only args.
130 : :
131 : : // get the function object that we want to set up (could be bytecode or native code)
132 : 9088264 : mp_obj_fun_bc_t *self = code_state->fun_bc;
133 : :
134 : : // Get cached n_state (rather than decode it again)
135 : 9088264 : size_t n_state = code_state->n_state;
136 : :
137 : : // Decode prelude
138 : 9088264 : size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args;
139 [ + + ]: 9647038 : MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args);
140 [ + + ]: 9088712 : MP_BC_PRELUDE_SIZE_DECODE(code_state->ip);
141 : 9088264 : (void)n_state_unused;
142 : 9088264 : (void)n_exc_stack_unused;
143 : :
144 : 9088264 : mp_obj_t *code_state_state = code_state->sp + 1;
145 : 9088264 : code_state->exc_sp_idx = 0;
146 : :
147 : : // zero out the local stack to begin with
148 : 9088264 : memset(code_state_state, 0, n_state * sizeof(*code_state->state));
149 : :
150 : 9088264 : const mp_obj_t *kwargs = args + n_args;
151 : :
152 : : // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
153 : 9088264 : mp_obj_t *var_pos_kw_args = &code_state_state[n_state - 1 - n_pos_args - n_kwonly_args];
154 : :
155 : : // check positional arguments
156 : :
157 [ + + ]: 9088264 : if (n_args > n_pos_args) {
158 : : // given more than enough arguments
159 [ + + ]: 8130 : if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) {
160 : 8 : fun_pos_args_mismatch(self, n_pos_args, n_args);
161 : : }
162 : : // put extra arguments in varargs tuple
163 : 8122 : *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args);
164 : 8122 : n_args = n_pos_args;
165 : : } else {
166 [ + + ]: 9080134 : if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
167 : 152 : DEBUG_printf("passing empty tuple as *args\n");
168 : 152 : *var_pos_kw_args-- = mp_const_empty_tuple;
169 : : }
170 : : // Apply processing and check below only if we don't have kwargs,
171 : : // otherwise, kw handling code below has own extensive checks.
172 [ + # + # ]: 9080134 : if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) {
173 [ + + ]: 9469189 : if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) {
174 : : // given enough arguments, but may need to use some default arguments
175 [ + + ]: 9788549 : for (size_t i = n_args; i < n_pos_args; i++) {
176 : 319364 : code_state_state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)];
177 : : }
178 : : } else {
179 : 4 : fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args);
180 : : }
181 : : }
182 : : }
183 : :
184 : : // copy positional args into state
185 [ + + ]: 19590075 : for (size_t i = 0; i < n_args; i++) {
186 : 10501823 : code_state_state[n_state - 1 - i] = args[i];
187 : : }
188 : :
189 : : // check keyword arguments
190 : :
191 [ + + # + ]: 9088723 : if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
192 : 0 : DEBUG_printf("Initial args: ");
193 : 0 : dump_args(code_state_state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
194 : :
195 : 0 : mp_obj_t dict = MP_OBJ_NULL;
196 [ + # ]: 0 : if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
197 : 124 : dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
198 : 124 : *var_pos_kw_args = dict;
199 : : }
200 : :
201 [ # + ]: 0 : for (size_t i = 0; i < n_kw; i++) {
202 : : // the keys in kwargs are expected to be qstr objects
203 : 0 : mp_obj_t wanted_arg_name = kwargs[2 * i];
204 : :
205 : : // get pointer to arg_names array
206 : 0 : const uint8_t *arg_names = code_state->ip;
207 : 0 : arg_names = mp_decode_uint_skip(arg_names);
208 : :
209 [ + + ]: 2309 : for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
210 : 1729 : qstr arg_qstr = mp_decode_uint(&arg_names);
211 : : #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
212 : 1729 : arg_qstr = self->context->constants.qstr_table[arg_qstr];
213 : : #endif
214 [ + + ]: 1729 : if (wanted_arg_name == MP_OBJ_NEW_QSTR(arg_qstr)) {
215 [ + + ]: 580 : if (code_state_state[n_state - 1 - j] != MP_OBJ_NULL) {
216 : 20 : error_multiple:
217 : 24 : mp_raise_msg_varg(&mp_type_TypeError,
218 : 24 : MP_ERROR_TEXT("function got multiple values for argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
219 : : }
220 : 560 : code_state_state[n_state - 1 - j] = kwargs[2 * i + 1];
221 : 560 : goto continue2;
222 : : }
223 : : }
224 : : // Didn't find name match with positional args
225 [ + + ]: 580 : if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
226 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
227 : : mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
228 : : #else
229 : 12 : mp_raise_msg_varg(&mp_type_TypeError,
230 : 12 : MP_ERROR_TEXT("unexpected keyword argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
231 : : #endif
232 : : }
233 : 568 : mp_map_elem_t *elem = mp_map_lookup(mp_obj_dict_get_map(dict), wanted_arg_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
234 [ + + ]: 568 : if (elem->value == MP_OBJ_NULL) {
235 : 564 : elem->value = kwargs[2 * i + 1];
236 : : } else {
237 : 4 : goto error_multiple;
238 : : }
239 : 1124 : continue2:;
240 : : }
241 : :
242 : 483 : DEBUG_printf("Args with kws flattened: ");
243 : 483 : dump_args(code_state_state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
244 : :
245 : : // fill in defaults for positional args
246 : 483 : mp_obj_t *d = &code_state_state[n_state - n_pos_args];
247 : 483 : mp_obj_t *s = &self->extra_args[n_def_pos_args - 1];
248 [ + + ]: 821 : for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) {
249 [ + + ]: 338 : if (*d == MP_OBJ_NULL) {
250 : 164 : *d = *s;
251 : : }
252 : : }
253 : :
254 : : DEBUG_printf("Args after filling default positional: ");
255 : : dump_args(code_state_state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
256 : :
257 : : // Check that all mandatory positional args are specified
258 [ + + ]: 1003 : while (d < &code_state_state[n_state]) {
259 [ + + ]: 524 : if (*d++ == MP_OBJ_NULL) {
260 : 4 : mp_raise_msg_varg(&mp_type_TypeError,
261 : 4 : MP_ERROR_TEXT("function missing required positional argument #%d"), &code_state_state[n_state] - d);
262 : : }
263 : : }
264 : :
265 : : // Check that all mandatory keyword args are specified
266 : : // Fill in default kw args if we have them
267 : 479 : const uint8_t *arg_names = mp_decode_uint_skip(code_state->ip);
268 [ + + ]: 1337 : for (size_t i = 0; i < n_pos_args; i++) {
269 : 858 : arg_names = mp_decode_uint_skip(arg_names);
270 : : }
271 [ + + ]: 791 : for (size_t i = 0; i < n_kwonly_args; i++) {
272 : 320 : qstr arg_qstr = mp_decode_uint(&arg_names);
273 : : #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
274 : 320 : arg_qstr = self->context->constants.qstr_table[arg_qstr];
275 : : #endif
276 [ + + ]: 320 : if (code_state_state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
277 : 80 : mp_map_elem_t *elem = NULL;
278 [ + + ]: 80 : if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
279 : 72 : elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, MP_OBJ_NEW_QSTR(arg_qstr), MP_MAP_LOOKUP);
280 : : }
281 [ + - ]: 72 : if (elem != NULL) {
282 : 72 : code_state_state[n_state - 1 - n_pos_args - i] = elem->value;
283 : : } else {
284 : 8 : mp_raise_msg_varg(&mp_type_TypeError,
285 : 8 : MP_ERROR_TEXT("function missing required keyword argument '%q'"), arg_qstr);
286 : : }
287 : : }
288 : : }
289 : :
290 : : } else {
291 : : // no keyword arguments given
292 [ + + ]: 9513931 : if (n_kwonly_args != 0) {
293 : 4 : mp_raise_TypeError(MP_ERROR_TEXT("function missing keyword-only argument"));
294 : : }
295 [ + + ]: 9513927 : if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
296 : 122 : *var_pos_kw_args = mp_obj_new_dict(0);
297 : : }
298 : : }
299 : :
300 : : // jump over code info (source file, argument names and line-number mapping)
301 : 9514398 : const uint8_t *ip = code_state->ip + n_info;
302 : :
303 : : // bytecode prelude: initialise closed over variables
304 [ + + ]: 9515554 : for (; n_cell; --n_cell) {
305 : 180199 : size_t local_num = *ip++;
306 : 1156 : code_state_state[n_state - 1 - local_num] =
307 : 180199 : mp_obj_new_cell(code_state_state[n_state - 1 - local_num]);
308 : : }
309 : :
310 : : // now that we skipped over the prelude, set the ip for the VM
311 : 9335355 : code_state->ip = ip;
312 : :
313 : 9335355 : DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args);
314 : 9335355 : dump_args(code_state_state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
315 : 9335355 : dump_args(code_state_state, n_state);
316 : 9335355 : }
317 : :
318 : : // On entry code_state should be allocated somewhere (stack/heap) and
319 : : // contain the following valid entries:
320 : : // - code_state->fun_bc should contain a pointer to the function object
321 : : // - code_state->n_state should be the number of objects in the local state
322 : 7960935 : void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
323 : 7960935 : code_state->ip = code_state->fun_bc->bytecode;
324 : 7960935 : code_state->sp = &code_state->state[0] - 1;
325 : : #if MICROPY_STACKLESS
326 : : code_state->prev = NULL;
327 : : #endif
328 : : #if MICROPY_PY_SYS_SETTRACE
329 : : code_state->prev_state = NULL;
330 : : code_state->frame = NULL;
331 : : #endif
332 : 7960935 : mp_setup_code_state_helper(code_state, n_args, n_kw, args);
333 : 8237303 : }
334 : :
335 : : #if MICROPY_EMIT_NATIVE
336 : : // On entry code_state should be allocated somewhere (stack/heap) and
337 : : // contain the following valid entries:
338 : : // - code_state->fun_bc should contain a pointer to the function object
339 : : // - code_state->n_state should be the number of objects in the local state
340 : 1063636 : void mp_setup_code_state_native(mp_code_state_native_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
341 [ + + ]: 1063636 : code_state->ip = mp_obj_fun_native_get_prelude_ptr(code_state->fun_bc);
342 : 1063636 : code_state->sp = &code_state->state[0] - 1;
343 : 1063636 : mp_setup_code_state_helper((mp_code_state_t *)code_state, n_args, n_kw, args);
344 : 1063604 : }
345 : : #endif
|