blob: 9f0e79c677dd156b40a16b3838b1b709735dd705 [file] [log] [blame]
Damien Georgeb534e1b2014-09-04 14:44:01 +01001/*
2 * This file is part of the Micro Python 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
Damien George51dfcb42015-01-01 20:27:54 +000032#include "py/nlr.h"
33#include "py/objfun.h"
Damien George3a3db4d2015-10-22 23:45:37 +010034#include "py/runtime0.h"
Damien George51dfcb42015-01-01 20:27:54 +000035#include "py/bc.h"
Damien Georgeb534e1b2014-09-04 14:44:01 +010036
37#if 0 // print debugging info
38#define DEBUG_PRINT (1)
39#else // don't print debugging info
Damien George7860c2a2014-11-05 21:16:41 +000040#define DEBUG_PRINT (0)
Damien Georgeb534e1b2014-09-04 14:44:01 +010041#define DEBUG_printf(...) (void)0
42#endif
43
44mp_uint_t mp_decode_uint(const byte **ptr) {
45 mp_uint_t unum = 0;
46 byte val;
47 const byte *p = *ptr;
48 do {
49 val = *p++;
50 unum = (unum << 7) | (val & 0x7f);
51 } while ((val & 0x80) != 0);
52 *ptr = p;
53 return unum;
54}
55
56STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
57#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
Damien George7f233842015-01-01 15:33:50 +000058 // generic message, used also for other argument issues
Damien George3a2171e2015-09-04 16:53:46 +010059 (void)f;
60 (void)expected;
61 (void)given;
Damien George7f233842015-01-01 15:33:50 +000062 mp_arg_error_terse_mismatch();
Damien Georgeb534e1b2014-09-04 14:44:01 +010063#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
Damien George3a2171e2015-09-04 16:53:46 +010064 (void)f;
Damien Georgeb534e1b2014-09-04 14:44:01 +010065 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
66 "function takes %d positional arguments but %d were given", expected, given));
67#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
68 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George044c4732015-04-11 13:03:37 +010069 "%q() takes %d positional arguments but %d were given",
70 mp_obj_fun_get_name(f), expected, given));
Damien Georgeb534e1b2014-09-04 14:44:01 +010071#endif
72}
73
74#if DEBUG_PRINT
Damien George42f3de92014-10-03 17:44:14 +000075STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010076 DEBUG_printf("%p: ", a);
Damien George42f3de92014-10-03 17:44:14 +000077 for (mp_uint_t i = 0; i < sz; i++) {
Damien Georgeb534e1b2014-09-04 14:44:01 +010078 DEBUG_printf("%p ", a[i]);
79 }
80 DEBUG_printf("\n");
81}
82#else
83#define dump_args(...) (void)0
84#endif
85
Damien George99886182015-04-06 22:38:53 +010086// On entry code_state should be allocated somewhere (stack/heap) and
87// contain the following valid entries:
Damien George99886182015-04-06 22:38:53 +010088// - code_state->ip should contain the offset in bytes from the start of
Damien George9b7f5832015-03-18 17:47:47 +000089// the bytecode chunk to just after n_state and n_exc_stack
Damien George99886182015-04-06 22:38:53 +010090// - code_state->n_state should be set to the state size (locals plus stack)
Damien Georgeb534e1b2014-09-04 14:44:01 +010091void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
92 // This function is pretty complicated. It's main aim is to be efficient in speed and RAM
93 // usage for the common case of positional only args.
94 mp_obj_fun_bc_t *self = self_in;
95 mp_uint_t n_state = code_state->n_state;
Damien Georgeb534e1b2014-09-04 14:44:01 +010096
Damien George9b7f5832015-03-18 17:47:47 +000097 // ip comes in as an offset into bytecode, so turn it into a true pointer
98 code_state->ip = self->bytecode + (mp_uint_t)code_state->ip;
99
Damien George713ea182015-10-23 01:23:11 +0100100 // store pointer to constant table
101 code_state->const_table = self->const_table;
102
Paul Sokolovsky20397572015-03-28 01:14:44 +0200103 #if MICROPY_STACKLESS
104 code_state->prev = NULL;
105 #endif
Damien George9b7f5832015-03-18 17:47:47 +0000106
Damien George3a3db4d2015-10-22 23:45:37 +0100107 // get params
108 mp_uint_t scope_flags = *code_state->ip++;
109 mp_uint_t n_pos_args = *code_state->ip++;
110 mp_uint_t n_kwonly_args = *code_state->ip++;
111 mp_uint_t n_def_pos_args = *code_state->ip++;
112
Damien Georgeb534e1b2014-09-04 14:44:01 +0100113 code_state->sp = &code_state->state[0] - 1;
114 code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
115
116 // zero out the local stack to begin with
117 memset(code_state->state, 0, n_state * sizeof(*code_state->state));
118
119 const mp_obj_t *kwargs = args + n_args;
120
121 // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
Damien George3a3db4d2015-10-22 23:45:37 +0100122 mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args];
Damien Georgeb534e1b2014-09-04 14:44:01 +0100123
124 // check positional arguments
125
Damien George3a3db4d2015-10-22 23:45:37 +0100126 if (n_args > n_pos_args) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100127 // given more than enough arguments
Damien George3a3db4d2015-10-22 23:45:37 +0100128 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) {
129 fun_pos_args_mismatch(self, n_pos_args, n_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100130 }
131 // put extra arguments in varargs tuple
Damien George3a3db4d2015-10-22 23:45:37 +0100132 *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args);
133 n_args = n_pos_args;
Damien Georgeb534e1b2014-09-04 14:44:01 +0100134 } else {
Damien George3a3db4d2015-10-22 23:45:37 +0100135 if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100136 DEBUG_printf("passing empty tuple as *args\n");
137 *var_pos_kw_args-- = mp_const_empty_tuple;
138 }
139 // Apply processing and check below only if we don't have kwargs,
140 // otherwise, kw handling code below has own extensive checks.
Damien George3a3db4d2015-10-22 23:45:37 +0100141 if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) {
142 if (n_args >= (mp_uint_t)(n_pos_args - n_def_pos_args)) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100143 // given enough arguments, but may need to use some default arguments
Damien George3a3db4d2015-10-22 23:45:37 +0100144 for (mp_uint_t i = n_args; i < n_pos_args; i++) {
145 code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)];
Damien Georgeb534e1b2014-09-04 14:44:01 +0100146 }
147 } else {
Damien George3a3db4d2015-10-22 23:45:37 +0100148 fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100149 }
150 }
151 }
152
153 // copy positional args into state
154 for (mp_uint_t i = 0; i < n_args; i++) {
155 code_state->state[n_state - 1 - i] = args[i];
156 }
157
158 // check keyword arguments
159
Damien George3a3db4d2015-10-22 23:45:37 +0100160 if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100161 DEBUG_printf("Initial args: ");
Damien George3a3db4d2015-10-22 23:45:37 +0100162 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100163
164 mp_obj_t dict = MP_OBJ_NULL;
Damien George3a3db4d2015-10-22 23:45:37 +0100165 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100166 dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
167 *var_pos_kw_args = dict;
168 }
169
Damien George9b7f5832015-03-18 17:47:47 +0000170 // get pointer to arg_names array
Damien George713ea182015-10-23 01:23:11 +0100171 const mp_obj_t *arg_names = (const mp_obj_t*)code_state->const_table;
Damien George1084b0f2014-10-25 15:07:02 +0100172
Damien Georgeb534e1b2014-09-04 14:44:01 +0100173 for (mp_uint_t i = 0; i < n_kw; i++) {
Damien George1084b0f2014-10-25 15:07:02 +0100174 mp_obj_t wanted_arg_name = kwargs[2 * i];
Damien George3a3db4d2015-10-22 23:45:37 +0100175 for (mp_uint_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
Damien George1084b0f2014-10-25 15:07:02 +0100176 if (wanted_arg_name == arg_names[j]) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100177 if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
178 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George044c4732015-04-11 13:03:37 +0100179 "function got multiple values for argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name)));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100180 }
181 code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
182 goto continue2;
183 }
184 }
185 // Didn't find name match with positional args
Damien George3a3db4d2015-10-22 23:45:37 +0100186 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100187 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
188 }
189 mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
190continue2:;
191 }
192
193 DEBUG_printf("Args with kws flattened: ");
Damien George3a3db4d2015-10-22 23:45:37 +0100194 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100195
196 // fill in defaults for positional args
Damien George3a3db4d2015-10-22 23:45:37 +0100197 mp_obj_t *d = &code_state->state[n_state - n_pos_args];
198 mp_obj_t *s = &self->extra_args[n_def_pos_args - 1];
199 for (mp_uint_t i = n_def_pos_args; i > 0; i--, d++, s--) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100200 if (*d == MP_OBJ_NULL) {
201 *d = *s;
202 }
203 }
204
205 DEBUG_printf("Args after filling default positional: ");
Damien George3a3db4d2015-10-22 23:45:37 +0100206 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100207
208 // Check that all mandatory positional args are specified
209 while (d < &code_state->state[n_state]) {
210 if (*d++ == MP_OBJ_NULL) {
211 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
212 "function missing required positional argument #%d", &code_state->state[n_state] - d));
213 }
214 }
215
216 // Check that all mandatory keyword args are specified
217 // Fill in default kw args if we have them
Damien George3a3db4d2015-10-22 23:45:37 +0100218 for (mp_uint_t i = 0; i < n_kwonly_args; i++) {
219 if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100220 mp_map_elem_t *elem = NULL;
Damien George3a3db4d2015-10-22 23:45:37 +0100221 if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
222 elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[n_def_pos_args])->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100223 }
224 if (elem != NULL) {
Damien George3a3db4d2015-10-22 23:45:37 +0100225 code_state->state[n_state - 1 - n_pos_args - i] = elem->value;
Damien Georgeb534e1b2014-09-04 14:44:01 +0100226 } else {
227 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
Damien George3a3db4d2015-10-22 23:45:37 +0100228 "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i])));
Damien Georgeb534e1b2014-09-04 14:44:01 +0100229 }
230 }
231 }
232
233 } else {
234 // no keyword arguments given
Damien George3a3db4d2015-10-22 23:45:37 +0100235 if (n_kwonly_args != 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100236 nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
237 "function missing keyword-only argument"));
238 }
Damien George3a3db4d2015-10-22 23:45:37 +0100239 if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100240 *var_pos_kw_args = mp_obj_new_dict(0);
241 }
242 }
243
Damien George9b7f5832015-03-18 17:47:47 +0000244 // get the ip and skip argument names
245 const byte *ip = code_state->ip;
Damien George9b7f5832015-03-18 17:47:47 +0000246
247 // store pointer to code_info and jump over it
248 {
249 code_state->code_info = ip;
250 const byte *ip2 = ip;
251 mp_uint_t code_info_size = mp_decode_uint(&ip2);
252 ip += code_info_size;
253 }
254
Damien Georgeb534e1b2014-09-04 14:44:01 +0100255 // bytecode prelude: initialise closed over variables
Damien Georgec9aa1882015-04-07 00:08:17 +0100256 mp_uint_t local_num;
257 while ((local_num = *ip++) != 255) {
258 code_state->state[n_state - 1 - local_num] =
259 mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100260 }
261
262 // now that we skipped over the prelude, set the ip for the VM
263 code_state->ip = ip;
264
Damien George3a3db4d2015-10-22 23:45:37 +0100265 DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args);
266 dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args);
Damien Georgeb534e1b2014-09-04 14:44:01 +0100267 dump_args(code_state->state, n_state);
268}