objfun.c 10.6 KB
Newer Older
1
2
3
4
5
6
7
8
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
9
#include "qstr.h"
10
#include "obj.h"
11
#include "objtuple.h"
12
#include "map.h"
13
14
15
16
17
18
19
20
#include "runtime.h"
#include "bc.h"

/******************************************************************************/
/* native functions                                                           */

// mp_obj_fun_native_t defined in obj.h

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
    if (n_kw && !self->is_kw) {
        nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
                                          "function does not take keyword arguments"));
    }

    if (self->n_args_min == self->n_args_max) {
        if (n_args != self->n_args_min) {
            nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
                                                     "function takes %d positional arguments but %d were given",
                                                     (const char*)(machine_int_t)self->n_args_min,
                                                     (const char*)(machine_int_t)n_args));
        }
    } else {
        if (n_args < self->n_args_min) {
            nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError,
                                                    "<fun name>() missing %d required positional arguments: <list of names of params>",
                                                    (const char*)(machine_int_t)(self->n_args_min - n_args)));
        } else if (n_args > self->n_args_max) {
            nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
                                                     "<fun name> expected at most %d arguments, got %d",
                                                     (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
        }
    }
}

47
48
mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
    assert(MP_OBJ_IS_TYPE(self_in, &fun_native_type));
49
    mp_obj_fun_native_t *self = self_in;
50

51
    // check number of arguments
52
53
    check_nargs(self, n_args, n_kw);

54
    if (self->is_kw) {
55
56
57
58
59
        // function allows keywords

        // TODO if n_kw==0 then don't allocate any memory for map (either pass NULL or allocate it on the heap)
        mp_map_t *kw_args = mp_map_new(n_kw);
        for (int i = 0; i < 2 * n_kw; i += 2) {
60
            mp_map_lookup(kw_args, args[n_args + i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = args[n_args + i + 1];
61
62
63
64
65
66
        }
        mp_obj_t res = ((mp_fun_kw_t)self->fun)(n_args, args, kw_args);
        // TODO clean up kw_args

        return res;

67
    } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
68
69
70
71
72
73
74
75
76
77
78
        // function requires a fixed number of arguments

        // dispatch function call
        switch (self->n_args_min) {
            case 0:
                return ((mp_fun_0_t)self->fun)();

            case 1:
                return ((mp_fun_1_t)self->fun)(args[0]);

            case 2:
79
                return ((mp_fun_2_t)self->fun)(args[0], args[1]);
80

81
            case 3:
82
                return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
83

84
85
86
87
88
89
            default:
                assert(0);
                return mp_const_none;
        }

    } else {
90
        // function takes a variable number of arguments, but no keywords
91

92
        return ((mp_fun_var_t)self->fun)(n_args, args);
93
94
95
96
97
98
    }
}

const mp_obj_type_t fun_native_type = {
    { &mp_const_type },
    "function",
99
    .call = fun_native_call,
100
101
};

102
103
// fun must have the correct signature for n_args fixed arguments
mp_obj_t rt_make_function_n(int n_args, void *fun) {
104
105
    mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
    o->base.type = &fun_native_type;
106
    o->is_kw = false;
107
108
    o->n_args_min = n_args;
    o->n_args_max = n_args;
109
110
111
112
    o->fun = fun;
    return o;
}

113
114
115
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun) {
    mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
    o->base.type = &fun_native_type;
116
    o->is_kw = false;
117
118
119
120
121
122
123
124
125
126
    o->n_args_min = n_args_min;
    o->n_args_max = ~((machine_uint_t)0);
    o->fun = fun;
    return o;
}

// min and max are inclusive
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
    mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
    o->base.type = &fun_native_type;
127
    o->is_kw = false;
128
129
130
131
132
133
134
135
136
137
138
    o->n_args_min = n_args_min;
    o->n_args_max = n_args_max;
    o->fun = fun;
    return o;
}

/******************************************************************************/
/* byte code functions                                                        */

typedef struct _mp_obj_fun_bc_t {
    mp_obj_base_t base;
139
    mp_map_t *globals;      // the context within which this function was defined
140
141
    short n_args;           // number of arguments this function takes
    short n_def_args;       // number of default arguments
142
143
    uint n_state;           // total state size for the executing function (incl args, locals, stack)
    const byte *bytecode;   // bytecode for the function
144
    mp_obj_t def_args[];    // values of default args, if any
145
146
} mp_obj_fun_bc_t;

147
mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
148
149
    mp_obj_fun_bc_t *self = self_in;

150
    if (n_args < self->n_args - self->n_def_args || n_args > self->n_args) {
151
        nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
152
    }
153
154
155
    if (n_kw != 0) {
        nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
    }
156

157
    uint use_def_args = self->n_args - n_args;
158
    mp_map_t *old_globals = rt_globals_get();
159
160
161
162
163
    rt_globals_set(self->globals);
    mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->def_args + self->n_def_args - use_def_args, use_def_args, self->n_state);
    rt_globals_set(old_globals);

    return result;
164
165
166
167
168
}

const mp_obj_type_t fun_bc_type = {
    { &mp_const_type },
    "function",
169
    .call = fun_bc_call,
170
171
};

172
173
174
175
176
177
178
mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args_in, uint n_state, const byte *code) {
    int n_def_args = 0;
    mp_obj_tuple_t *def_args = def_args_in;
    if (def_args != MP_OBJ_NULL) {
        n_def_args = def_args->len;
    }
    mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_def_args);
179
    o->base.type = &fun_bc_type;
180
    o->globals = rt_globals_get();
181
    o->n_args = n_args;
182
    o->n_def_args = n_def_args;
183
    o->n_state = n_state;
184
    o->bytecode = code;
185
186
187
    if (def_args != MP_OBJ_NULL) {
        memcpy(o->def_args, def_args->items, n_def_args * sizeof(*o->def_args));
    }
188
189
190
    return o;
}

191
192
193
194
195
196
197
198
void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code) {
    assert(MP_OBJ_IS_TYPE(self_in, &fun_bc_type));
    mp_obj_fun_bc_t *self = self_in;
    *n_args = self->n_args;
    *n_state = self->n_state;
    *code = self->bytecode;
}

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/******************************************************************************/
/* inline assembler functions                                                 */

typedef struct _mp_obj_fun_asm_t {
    mp_obj_base_t base;
    int n_args;
    void *fun;
} mp_obj_fun_asm_t;

typedef machine_uint_t (*inline_asm_fun_0_t)();
typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);

// convert a Micro Python object to a sensible value for inline asm
machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
    // TODO for byte_array, pass pointer to the array
    if (MP_OBJ_IS_SMALL_INT(obj)) {
        return MP_OBJ_SMALL_INT_VALUE(obj);
    } else if (obj == mp_const_none) {
        return 0;
    } else if (obj == mp_const_false) {
        return 0;
    } else if (obj == mp_const_true) {
        return 1;
224
    } else if (MP_OBJ_IS_STR(obj)) {
225
        // pointer to the string (it's probably constant though!)
226
227
        uint l;
        return (machine_uint_t)mp_obj_str_get_data(obj, &l);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#if MICROPY_ENABLE_FLOAT
    } else if (MP_OBJ_IS_TYPE(obj, &float_type)) {
        // convert float to int (could also pass in float registers)
        return (machine_int_t)mp_obj_float_get(obj);
#endif
    } else if (MP_OBJ_IS_TYPE(obj, &tuple_type)) {
        // pointer to start of tuple (could pass length, but then could use len(x) for that)
        uint len;
        mp_obj_t *items;
        mp_obj_tuple_get(obj, &len, &items);
        return (machine_uint_t)items;
    } else if (MP_OBJ_IS_TYPE(obj, &list_type)) {
        // pointer to start of list (could pass length, but then could use len(x) for that)
        uint len;
        mp_obj_t *items;
        mp_obj_list_get(obj, &len, &items);
        return (machine_uint_t)items;
    } else {
        // just pass along a pointer to the object
        return (machine_uint_t)obj;
    }
}

// convert a return value from inline asm to a sensible Micro Python object
mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
    return MP_OBJ_NEW_SMALL_INT(val);
}

256
mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
257
258
259
    mp_obj_fun_asm_t *self = self_in;

    if (n_args != self->n_args) {
260
        nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
261
    }
262
263
264
    if (n_kw != 0) {
        nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
    }
265
266
267
268
269
270
271

    machine_uint_t ret;
    if (n_args == 0) {
        ret = ((inline_asm_fun_0_t)self->fun)();
    } else if (n_args == 1) {
        ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
    } else if (n_args == 2) {
272
        ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
273
    } else if (n_args == 3) {
274
        ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
275
276
277
278
279
280
281
282
283
284
285
    } else {
        assert(0);
        ret = 0;
    }

    return convert_val_from_inline_asm(ret);
}

static const mp_obj_type_t fun_asm_type = {
    { &mp_const_type },
    "function",
286
    .call = fun_asm_call,
287
288
289
290
291
292
293
294
295
};

mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
    mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
    o->base.type = &fun_asm_type;
    o->n_args = n_args;
    o->fun = fun;
    return o;
}