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 | |
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 |
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 |
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 |
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 | |
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 |
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 | |
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) |
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 |
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 |
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 |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |