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  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
31 
32 #include "py/runtime.h"
33 #include "py/smallint.h"
34 #include "py/nativeglue.h"
35 #include "py/gc.h"
36 
37 #if MICROPY_DEBUG_VERBOSE // print debugging info
38 #define DEBUG_printf DEBUG_printf
39 #else // don't print debugging info
40 #define DEBUG_printf(...) (void)0
41 #endif
42 
43 #if MICROPY_EMIT_NATIVE
44 
mp_native_type_from_qstr(qstr qst)45 int mp_native_type_from_qstr(qstr qst) {
46     switch (qst) {
47         case MP_QSTR_object:
48             return MP_NATIVE_TYPE_OBJ;
49         case MP_QSTR_bool:
50             return MP_NATIVE_TYPE_BOOL;
51         case MP_QSTR_int:
52             return MP_NATIVE_TYPE_INT;
53         case MP_QSTR_uint:
54             return MP_NATIVE_TYPE_UINT;
55         case MP_QSTR_ptr:
56             return MP_NATIVE_TYPE_PTR;
57         case MP_QSTR_ptr8:
58             return MP_NATIVE_TYPE_PTR8;
59         case MP_QSTR_ptr16:
60             return MP_NATIVE_TYPE_PTR16;
61         case MP_QSTR_ptr32:
62             return MP_NATIVE_TYPE_PTR32;
63         default:
64             return -1;
65     }
66 }
67 
68 // convert a MicroPython object to a valid native value based on type
mp_native_from_obj(mp_obj_t obj,mp_uint_t type)69 mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) {
70     DEBUG_printf("mp_native_from_obj(%p, " UINT_FMT ")\n", obj, type);
71     switch (type & 0xf) {
72         case MP_NATIVE_TYPE_OBJ:
73             return (mp_uint_t)obj;
74         case MP_NATIVE_TYPE_BOOL:
75             return mp_obj_is_true(obj);
76         case MP_NATIVE_TYPE_INT:
77         case MP_NATIVE_TYPE_UINT:
78             return mp_obj_get_int_truncated(obj);
79         default: { // cast obj to a pointer
80             mp_buffer_info_t bufinfo;
81             if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) {
82                 return (mp_uint_t)bufinfo.buf;
83             } else {
84                 // assume obj is an integer that represents an address
85                 return mp_obj_get_int_truncated(obj);
86             }
87         }
88     }
89 }
90 
91 #endif
92 
93 #if MICROPY_EMIT_MACHINE_CODE
94 
95 // convert a native value to a MicroPython object based on type
mp_native_to_obj(mp_uint_t val,mp_uint_t type)96 mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) {
97     DEBUG_printf("mp_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
98     switch (type & 0xf) {
99         case MP_NATIVE_TYPE_OBJ:
100             return (mp_obj_t)val;
101         case MP_NATIVE_TYPE_BOOL:
102             return mp_obj_new_bool(val);
103         case MP_NATIVE_TYPE_INT:
104             return mp_obj_new_int(val);
105         case MP_NATIVE_TYPE_UINT:
106             return mp_obj_new_int_from_uint(val);
107         default: // a pointer
108             // we return just the value of the pointer as an integer
109             return mp_obj_new_int_from_uint(val);
110     }
111 }
112 
113 #endif
114 
115 #if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER
116 
117 #if !MICROPY_PY_BUILTINS_SET
mp_obj_new_set(size_t n_args,mp_obj_t * items)118 mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) {
119     (void)n_args;
120     (void)items;
121     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("set unsupported"));
122 }
123 
mp_obj_set_store(mp_obj_t self_in,mp_obj_t item)124 void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
125     (void)self_in;
126     (void)item;
127     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("set unsupported"));
128 }
129 #endif
130 
131 #if !MICROPY_PY_BUILTINS_SLICE
mp_obj_new_slice(mp_obj_t ostart,mp_obj_t ostop,mp_obj_t ostep)132 mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
133     (void)ostart;
134     (void)ostop;
135     (void)ostep;
136     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("slice unsupported"));
137 }
138 #endif
139 
mp_native_swap_globals(mp_obj_dict_t * new_globals)140 STATIC mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) {
141     if (new_globals == NULL) {
142         // Globals were the originally the same so don't restore them
143         return NULL;
144     }
145     mp_obj_dict_t *old_globals = mp_globals_get();
146     if (old_globals == new_globals) {
147         // Don't set globals if they are the same, and return NULL to indicate this
148         return NULL;
149     }
150     mp_globals_set(new_globals);
151     return old_globals;
152 }
153 
154 // wrapper that accepts n_args and n_kw in one argument
155 // (native emitter can only pass at most 3 arguments to a function)
mp_native_call_function_n_kw(mp_obj_t fun_in,size_t n_args_kw,const mp_obj_t * args)156 STATIC mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) {
157     return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
158 }
159 
160 // wrapper that makes raise obj and raises it
161 // END_FINALLY opcode requires that we don't raise if o==None
mp_native_raise(mp_obj_t o)162 STATIC void mp_native_raise(mp_obj_t o) {
163     if (o != MP_OBJ_NULL && o != mp_const_none) {
164         nlr_raise(mp_make_raise_obj(o));
165     }
166 }
167 
168 // wrapper that handles iterator buffer
mp_native_getiter(mp_obj_t obj,mp_obj_iter_buf_t * iter)169 STATIC mp_obj_t mp_native_getiter(mp_obj_t obj, mp_obj_iter_buf_t *iter) {
170     if (iter == NULL) {
171         return mp_getiter(obj, NULL);
172     } else {
173         obj = mp_getiter(obj, iter);
174         if (obj != MP_OBJ_FROM_PTR(iter)) {
175             // Iterator didn't use the stack so indicate that with MP_OBJ_NULL.
176             iter->base.type = MP_OBJ_NULL;
177             iter->buf[0] = obj;
178         }
179         return NULL;
180     }
181 }
182 
183 // wrapper that handles iterator buffer
mp_native_iternext(mp_obj_iter_buf_t * iter)184 STATIC mp_obj_t mp_native_iternext(mp_obj_iter_buf_t *iter) {
185     mp_obj_t obj;
186     if (iter->base.type == MP_OBJ_NULL) {
187         obj = iter->buf[0];
188     } else {
189         obj = MP_OBJ_FROM_PTR(iter);
190     }
191     return mp_iternext(obj);
192 }
193 
mp_native_yield_from(mp_obj_t gen,mp_obj_t send_value,mp_obj_t * ret_value)194 STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value) {
195     mp_vm_return_kind_t ret_kind;
196     nlr_buf_t nlr_buf;
197     mp_obj_t throw_value = *ret_value;
198     if (nlr_push(&nlr_buf) == 0) {
199         if (throw_value != MP_OBJ_NULL) {
200             send_value = MP_OBJ_NULL;
201         }
202         ret_kind = mp_resume(gen, send_value, throw_value, ret_value);
203         nlr_pop();
204     } else {
205         ret_kind = MP_VM_RETURN_EXCEPTION;
206         *ret_value = nlr_buf.ret_val;
207     }
208 
209     if (ret_kind == MP_VM_RETURN_YIELD) {
210         return true;
211     } else if (ret_kind == MP_VM_RETURN_NORMAL) {
212         if (*ret_value == MP_OBJ_STOP_ITERATION) {
213             *ret_value = mp_const_none;
214         }
215     } else {
216         assert(ret_kind == MP_VM_RETURN_EXCEPTION);
217         if (!mp_obj_exception_match(*ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {
218             nlr_raise(*ret_value);
219         }
220         *ret_value = mp_obj_exception_get_value(*ret_value);
221     }
222 
223     if (throw_value != MP_OBJ_NULL && mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) {
224         nlr_raise(mp_make_raise_obj(throw_value));
225     }
226 
227     return false;
228 }
229 
230 #if !MICROPY_PY_BUILTINS_FLOAT
231 
mp_obj_new_float_from_f(float f)232 STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
233     (void)f;
234     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
235 }
236 
mp_obj_new_float_from_d(double d)237 STATIC mp_obj_t mp_obj_new_float_from_d(double d) {
238     (void)d;
239     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
240 }
241 
mp_obj_get_float_to_f(mp_obj_t o)242 STATIC float mp_obj_get_float_to_f(mp_obj_t o) {
243     (void)o;
244     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
245 }
246 
mp_obj_get_float_to_d(mp_obj_t o)247 STATIC double mp_obj_get_float_to_d(mp_obj_t o) {
248     (void)o;
249     mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
250 }
251 
252 #endif
253 
254 // these must correspond to the respective enum in nativeglue.h
255 const mp_fun_table_t mp_fun_table = {
256     mp_const_none,
257     mp_const_false,
258     mp_const_true,
259     mp_native_from_obj,
260     mp_native_to_obj,
261     mp_native_swap_globals,
262     mp_load_name,
263     mp_load_global,
264     mp_load_build_class,
265     mp_load_attr,
266     mp_load_method,
267     mp_load_super_method,
268     mp_store_name,
269     mp_store_global,
270     mp_store_attr,
271     mp_obj_subscr,
272     mp_obj_is_true,
273     mp_unary_op,
274     mp_binary_op,
275     mp_obj_new_tuple,
276     mp_obj_new_list,
277     mp_obj_new_dict,
278     mp_obj_new_set,
279     mp_obj_set_store,
280     mp_obj_list_append,
281     mp_obj_dict_store,
282     mp_make_function_from_raw_code,
283     mp_native_call_function_n_kw,
284     mp_call_method_n_kw,
285     mp_call_method_n_kw_var,
286     mp_native_getiter,
287     mp_native_iternext,
288     #if MICROPY_NLR_SETJMP
289     nlr_push_tail,
290     #else
291     nlr_push,
292     #endif
293     nlr_pop,
294     mp_native_raise,
295     mp_import_name,
296     mp_import_from,
297     mp_import_all,
298     mp_obj_new_slice,
299     mp_unpack_sequence,
300     mp_unpack_ex,
301     mp_delete_name,
302     mp_delete_global,
303     mp_make_closure_from_raw_code,
304     mp_arg_check_num_sig,
305     mp_setup_code_state,
306     mp_small_int_floor_divide,
307     mp_small_int_modulo,
308     mp_native_yield_from,
309     #if MICROPY_NLR_SETJMP
310     setjmp,
311     #else
312     NULL,
313     #endif
314     // Additional entries for dynamic runtime, starts at index 50
315     memset,
316     memmove,
317     gc_realloc,
318     mp_printf,
319     mp_vprintf,
320     mp_raise_msg,
321     mp_obj_get_type,
322     mp_obj_new_str,
323     mp_obj_new_bytes,
324     mp_obj_new_bytearray_by_ref,
325     mp_obj_new_float_from_f,
326     mp_obj_new_float_from_d,
327     mp_obj_get_float_to_f,
328     mp_obj_get_float_to_d,
329     mp_get_buffer_raise,
330     mp_get_stream_raise,
331     &mp_plat_print,
332     &mp_type_type,
333     &mp_type_str,
334     &mp_type_list,
335     &mp_type_dict,
336     &mp_type_fun_builtin_0,
337     &mp_type_fun_builtin_1,
338     &mp_type_fun_builtin_2,
339     &mp_type_fun_builtin_3,
340     &mp_type_fun_builtin_var,
341     &mp_stream_read_obj,
342     &mp_stream_readinto_obj,
343     &mp_stream_unbuffered_readline_obj,
344     &mp_stream_write_obj,
345 };
346 
347 #endif // MICROPY_EMIT_NATIVE
348