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/runtime.h"
33#include "py/bc0.h"
34#include "py/bc.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#if !MICROPY_PERSISTENT_CODE
44
45mp_uint_t mp_decode_uint(const byte **ptr) {
46 mp_uint_t unum = 0;
47 byte val;
48 const byte *p = *ptr;
49 do {
50 val = *p++;
51 unum = (unum << 7) | (val & 0x7f);
52 } while ((val & 0x80) != 0);
53 *ptr = p;
54 return unum;
55}
56
57// This function is used to help reduce stack usage at the caller, for the case when
58// the caller doesn't need to increase the ptr argument. If ptr is a local variable
59// and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler
60// must allocate a slot on the stack for ptr, and this slot cannot be reused for
61// anything else in the function because the pointer may have been stored in a global
62// and reused later in the function.
63mp_uint_t mp_decode_uint_value(const byte *ptr) {
64 return mp_decode_uint(&ptr);
65}
66
67// This function is used to help reduce stack usage at the caller, for the case when
68// the caller doesn't need the actual value and just wants to skip over it.
69const byte *mp_decode_uint_skip(const byte *ptr) {
70 while ((*ptr++) & 0x80) {
71 }
72 return ptr;
73}
74
75#endif
76
77STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
78 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
79 // generic message, used also for other argument issues
80 (void)f;
81 (void)expected;
82 (void)given;
83 mp_arg_error_terse_mismatch();
84 #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
85 (void)f;
86 mp_raise_msg_varg(&mp_type_TypeError,
87 MP_ERROR_TEXT("function takes %d positional arguments but %d were given"), expected, given);
88 #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
89 mp_raise_msg_varg(&mp_type_TypeError,
90 MP_ERROR_TEXT("%q() takes %d positional arguments but %d were given"),
91 mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given);
92 #endif
93}
94
95#if DEBUG_PRINT
96STATIC void dump_args(const mp_obj_t *a, size_t sz) {
97 DEBUG_printf("%p: ", a);
98 for (size_t i = 0; i < sz; i++) {
99 DEBUG_printf("%p ", a[i]);
100 }
101 DEBUG_printf("\n");
102}
103#else
104#define dump_args(...) (void)0
105#endif
106
107// On entry code_state should be allocated somewhere (stack/heap) and
108// contain the following valid entries:
109// - code_state->fun_bc should contain a pointer to the function object
110// - code_state->ip should contain the offset in bytes from the pointer
111// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native)
112void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
113 // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
114 // usage for the common case of positional only args.
115
116 // get the function object that we want to set up (could be bytecode or native code)
117 mp_obj_fun_bc_t *self = code_state->fun_bc;
118
119 // ip comes in as an offset into bytecode, so turn it into a true pointer
120 code_state->ip = self->bytecode + (size_t)code_state->ip;
121
122 #if MICROPY_STACKLESS
123 code_state->prev = NULL;
124 #endif
125
126 #if MICROPY_PY_SYS_SETTRACE
127 code_state->prev_state = NULL;
128 code_state->frame = NULL;
129 #endif
130
131 // Get cached n_state (rather than decode it again)
132 size_t n_state = code_state->n_state;
133
134 // Decode prelude
135 size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args;
136 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);
137 (void)n_state_unused;
138 (void)n_exc_stack_unused;
139
140 code_state->sp = &code_state->state[0] - 1;
141 code_state->exc_sp_idx = 0;
142
143 // zero out the local stack to begin with
144 memset(code_state->state, 0, n_state * sizeof(*code_state->state));
145
146 const mp_obj_t *kwargs = args + n_args;
147
148 // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
149 mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args];
150
151 // check positional arguments
152
153 if (n_args > n_pos_args) {
154 // given more than enough arguments
155 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) {
156 fun_pos_args_mismatch(self, n_pos_args, n_args);
157 }
158 // put extra arguments in varargs tuple
159 *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args);
160 n_args = n_pos_args;
161 } else {
162 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
163 DEBUG_printf("passing empty tuple as *args\n");
164 *var_pos_kw_args-- = mp_const_empty_tuple;
165 }
166 // Apply processing and check below only if we don't have kwargs,
167 // otherwise, kw handling code below has own extensive checks.
168 if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) {
169 if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) {
170 // given enough arguments, but may need to use some default arguments
171 for (size_t i = n_args; i < n_pos_args; i++) {
172 code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)];
173 }
174 } else {
175 fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args);
176 }
177 }
178 }
179
180 // copy positional args into state
181 for (size_t i = 0; i < n_args; i++) {
182 code_state->state[n_state - 1 - i] = args[i];
183 }
184
185 // check keyword arguments
186
187 if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
188 DEBUG_printf("Initial args: ");
189 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
190
191 mp_obj_t dict = MP_OBJ_NULL;
192 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
193 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
194 *var_pos_kw_args = dict;
195 }
196
197 // get pointer to arg_names array
198 const mp_obj_t *arg_names = (const mp_obj_t *)self->const_table;
199
200 for (size_t i = 0; i < n_kw; i++) {
201 // the keys in kwargs are expected to be qstr objects
202 mp_obj_t wanted_arg_name = kwargs[2 * i];
203 for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
204 if (wanted_arg_name == arg_names[j]) {
205 if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
206 mp_raise_msg_varg(&mp_type_TypeError,
207 MP_ERROR_TEXT("function got multiple values for argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
208 }
209 code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
210 goto continue2;
211 }
212 }
213 // Didn't find name match with positional args
214 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
215 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
216 mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
217 #else
218 mp_raise_msg_varg(&mp_type_TypeError,
219 MP_ERROR_TEXT("unexpected keyword argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
220 #endif
221 }
222 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
223 continue2:;
224 }
225
226 DEBUG_printf("Args with kws flattened: ");
227 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
228
229 // fill in defaults for positional args
230 mp_obj_t *d = &code_state->state[n_state - n_pos_args];
231 mp_obj_t *s = &self->extra_args[n_def_pos_args - 1];
232 for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) {
233 if (*d == MP_OBJ_NULL) {
234 *d = *s;
235 }
236 }
237
238 DEBUG_printf("Args after filling default positional: ");
239 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
240
241 // Check that all mandatory positional args are specified
242 while (d < &code_state->state[n_state]) {
243 if (*d++ == MP_OBJ_NULL) {
244 mp_raise_msg_varg(&mp_type_TypeError,
245 MP_ERROR_TEXT("function missing required positional argument #%d"), &code_state->state[n_state] - d);
246 }
247 }
248
249 // Check that all mandatory keyword args are specified
250 // Fill in default kw args if we have them
251 for (size_t i = 0; i < n_kwonly_args; i++) {
252 if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
253 mp_map_elem_t *elem = NULL;
254 if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
255 elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP);
256 }
257 if (elem != NULL) {
258 code_state->state[n_state - 1 - n_pos_args - i] = elem->value;
259 } else {
260 mp_raise_msg_varg(&mp_type_TypeError,
261 MP_ERROR_TEXT("function missing required keyword argument '%q'"), MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]));
262 }
263 }
264 }
265
266 } else {
267 // no keyword arguments given
268 if (n_kwonly_args != 0) {
269 mp_raise_TypeError(MP_ERROR_TEXT("function missing keyword-only argument"));
270 }
271 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
272 *var_pos_kw_args = mp_obj_new_dict(0);
273 }
274 }
275
276 // read the size part of the prelude
277 const byte *ip = code_state->ip;
278 MP_BC_PRELUDE_SIZE_DECODE(ip);
279
280 // jump over code info (source file and line-number mapping)
281 ip += n_info;
282
283 // bytecode prelude: initialise closed over variables
284 for (; n_cell; --n_cell) {
285 size_t local_num = *ip++;
286 code_state->state[n_state - 1 - local_num] =
287 mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
288 }
289
290 #if !MICROPY_PERSISTENT_CODE
291 // so bytecode is aligned
292 ip = MP_ALIGN(ip, sizeof(mp_uint_t));
293 #endif
294
295 // now that we skipped over the prelude, set the ip for the VM
296 code_state->ip = ip;
297
298 DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args);
299 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
300 dump_args(code_state->state, n_state);
301}
302
303#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
304
305// The following table encodes the number of bytes that a specific opcode
306// takes up. Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE.
307// There are 4 special opcodes that have an extra byte only when
308// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr):
309// MP_BC_LOAD_NAME
310// MP_BC_LOAD_GLOBAL
311// MP_BC_LOAD_ATTR
312// MP_BC_STORE_ATTR
313uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) {
314 uint f = MP_BC_FORMAT(*ip);
315 const byte *ip_start = ip;
316 if (f == MP_BC_FORMAT_QSTR) {
317 if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
318 if (*ip == MP_BC_LOAD_NAME
319 || *ip == MP_BC_LOAD_GLOBAL
320 || *ip == MP_BC_LOAD_ATTR
321 || *ip == MP_BC_STORE_ATTR) {
322 ip += 1;
323 }
324 }
325 ip += 3;
326 } else {
327 int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0;
328 ip += 1;
329 if (f == MP_BC_FORMAT_VAR_UINT) {
330 if (count_var_uint) {
331 while ((*ip++ & 0x80) != 0) {
332 }
333 }
334 } else if (f == MP_BC_FORMAT_OFFSET) {
335 ip += 2;
336 }
337 ip += extra_byte;
338 }
339 *opcode_size = ip - ip_start;
340 return f;
341}
342
343#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
344