1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2019 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 #ifndef MICROPY_INCLUDED_PY_DYNRUNTIME_H
27 #define MICROPY_INCLUDED_PY_DYNRUNTIME_H
28 
29 // This header file contains definitions to dynamically implement the static
30 // MicroPython runtime API defined in py/obj.h and py/runtime.h.
31 
32 #include "py/nativeglue.h"
33 #include "py/objstr.h"
34 #include "py/objtype.h"
35 
36 #if !MICROPY_ENABLE_DYNRUNTIME
37 #error "dynruntime.h included in non-dynamic-module build."
38 #endif
39 
40 #undef MP_ROM_QSTR
41 #undef MP_OBJ_QSTR_VALUE
42 #undef MP_OBJ_NEW_QSTR
43 #undef mp_const_none
44 #undef mp_const_false
45 #undef mp_const_true
46 #undef mp_const_empty_tuple
47 #undef nlr_raise
48 
49 /******************************************************************************/
50 // Memory allocation
51 
52 #define m_malloc(n)                     (m_malloc_dyn((n)))
53 #define m_free(ptr)                     (m_free_dyn((ptr)))
54 #define m_realloc(ptr, new_num_bytes)   (m_realloc_dyn((ptr), (new_num_bytes)))
55 
m_malloc_dyn(size_t n)56 static inline void *m_malloc_dyn(size_t n) {
57     // TODO won't raise on OOM
58     return mp_fun_table.realloc_(NULL, n, false);
59 }
60 
m_free_dyn(void * ptr)61 static inline void m_free_dyn(void *ptr) {
62     mp_fun_table.realloc_(ptr, 0, false);
63 }
64 
m_realloc_dyn(void * ptr,size_t new_num_bytes)65 static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
66     // TODO won't raise on OOM
67     return mp_fun_table.realloc_(ptr, new_num_bytes, true);
68 }
69 
70 /******************************************************************************/
71 // Printing
72 
73 #define mp_plat_print               (*mp_fun_table.plat_print)
74 #define mp_printf(p, ...)           (mp_fun_table.printf_((p), __VA_ARGS__))
75 #define mp_vprintf(p, fmt, args)    (mp_fun_table.vprintf_((p), (fmt), (args)))
76 
77 /******************************************************************************/
78 // Types and objects
79 
80 #define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_##x
81 
82 #define mp_type_type                        (*mp_fun_table.type_type)
83 #define mp_type_str                         (*mp_fun_table.type_str)
84 #define mp_type_tuple                       (*((mp_obj_base_t *)mp_const_empty_tuple)->type)
85 #define mp_type_list                        (*mp_fun_table.type_list)
86 #define mp_type_EOFError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))
87 #define mp_type_IndexError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))
88 #define mp_type_KeyError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_KeyError)))
89 #define mp_type_NotImplementedError         (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_NotImplementedError)))
90 #define mp_type_RuntimeError                (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_RuntimeError)))
91 #define mp_type_TypeError                   (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_TypeError)))
92 #define mp_type_ValueError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_ValueError)))
93 
94 #define mp_stream_read_obj                  (*mp_fun_table.stream_read_obj)
95 #define mp_stream_readinto_obj              (*mp_fun_table.stream_readinto_obj)
96 #define mp_stream_unbuffered_readline_obj   (*mp_fun_table.stream_unbuffered_readline_obj)
97 #define mp_stream_write_obj                 (*mp_fun_table.stream_write_obj)
98 
99 #define mp_const_none                       ((mp_obj_t)mp_fun_table.const_none)
100 #define mp_const_false                      ((mp_obj_t)mp_fun_table.const_false)
101 #define mp_const_true                       ((mp_obj_t)mp_fun_table.const_true)
102 #define mp_const_empty_tuple                (mp_fun_table.new_tuple(0, NULL))
103 
104 #define mp_obj_new_bool(b)                  ((b) ? (mp_obj_t)mp_fun_table.const_true : (mp_obj_t)mp_fun_table.const_false)
105 #define mp_obj_new_int(i)                   (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_INT))
106 #define mp_obj_new_int_from_uint(i)         (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_UINT))
107 #define mp_obj_new_str(data, len)           (mp_fun_table.obj_new_str((data), (len)))
108 #define mp_obj_new_str_of_type(t, d, l)     (mp_obj_new_str_of_type_dyn((t), (d), (l)))
109 #define mp_obj_new_bytes(data, len)         (mp_fun_table.obj_new_bytes((data), (len)))
110 #define mp_obj_new_bytearray_by_ref(n, i)   (mp_fun_table.obj_new_bytearray_by_ref((n), (i)))
111 #define mp_obj_new_tuple(n, items)          (mp_fun_table.new_tuple((n), (items)))
112 #define mp_obj_new_list(n, items)           (mp_fun_table.new_list((n), (items)))
113 
114 #define mp_obj_get_type(o)                  (mp_fun_table.obj_get_type((o)))
115 #define mp_obj_cast_to_native_base(o, t)    (mp_obj_cast_to_native_base_dyn((o), (t)))
116 #define mp_obj_get_int(o)                   (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT))
117 #define mp_obj_get_int_truncated(o)         (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_UINT))
118 #define mp_obj_str_get_str(s)               (mp_obj_str_get_data_dyn((s), NULL))
119 #define mp_obj_str_get_data(o, len)         (mp_obj_str_get_data_dyn((o), (len)))
120 #define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl)))
121 #define mp_get_stream_raise(s, flags)       (mp_fun_table.get_stream_raise((s), (flags)))
122 
123 #define mp_obj_len(o)                       (mp_obj_len_dyn(o))
124 #define mp_obj_subscr(base, index, val)     (mp_fun_table.obj_subscr((base), (index), (val)))
125 #define mp_obj_get_array(o, len, items)     (mp_obj_get_array_dyn((o), (len), (items)))
126 #define mp_obj_list_append(list, item)      (mp_fun_table.list_append((list), (item)))
127 
mp_obj_new_str_of_type_dyn(const mp_obj_type_t * type,const byte * data,size_t len)128 static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte *data, size_t len) {
129     if (type == &mp_type_str) {
130         return mp_obj_new_str((const char *)data, len);
131     } else {
132         return mp_obj_new_bytes(data, len);
133     }
134 }
135 
mp_obj_cast_to_native_base_dyn(mp_obj_t self_in,mp_const_obj_t native_type)136 static inline mp_obj_t mp_obj_cast_to_native_base_dyn(mp_obj_t self_in, mp_const_obj_t native_type) {
137     const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
138 
139     if (MP_OBJ_FROM_PTR(self_type) == native_type) {
140         return self_in;
141     } else if (self_type->parent != native_type) {
142         // The self_in object is not a direct descendant of native_type, so fail the cast.
143         // This is a very simple version of mp_obj_is_subclass_fast that could be improved.
144         return MP_OBJ_NULL;
145     } else {
146         mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);
147         return self->subobj[0];
148     }
149 }
150 
mp_obj_str_get_data_dyn(mp_obj_t o,size_t * l)151 static inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) {
152     mp_buffer_info_t bufinfo;
153     mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_READ);
154     if (l != NULL) {
155         *l = bufinfo.len;
156     }
157     return bufinfo.buf;
158 }
159 
mp_obj_len_dyn(mp_obj_t o)160 static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
161     // If bytes implemented MP_UNARY_OP_LEN could use: mp_unary_op(MP_UNARY_OP_LEN, o)
162     return mp_fun_table.call_function_n_kw(mp_fun_table.load_name(MP_QSTR_len), 1, &o);
163 }
164 
165 /******************************************************************************/
166 // General runtime functions
167 
168 #define mp_load_name(qst)                 (mp_fun_table.load_name((qst)))
169 #define mp_load_global(qst)               (mp_fun_table.load_global((qst)))
170 #define mp_load_attr(base, attr)          (mp_fun_table.load_attr((base), (attr)))
171 #define mp_load_method(base, attr, dest)  (mp_fun_table.load_method((base), (attr), (dest)))
172 #define mp_load_super_method(attr, dest)  (mp_fun_table.load_super_method((attr), (dest)))
173 #define mp_store_name(qst, obj)           (mp_fun_table.store_name((qst), (obj)))
174 #define mp_store_global(qst, obj)         (mp_fun_table.store_global((qst), (obj)))
175 #define mp_store_attr(base, attr, val)    (mp_fun_table.store_attr((base), (attr), (val)))
176 
177 #define mp_unary_op(op, obj)        (mp_fun_table.unary_op((op), (obj)))
178 #define mp_binary_op(op, lhs, rhs)  (mp_fun_table.binary_op((op), (lhs), (rhs)))
179 
180 #define mp_make_function_from_raw_code(rc, def_args, def_kw_args) \
181     (mp_fun_table.make_function_from_raw_code((rc), (def_args), (def_kw_args)))
182 
183 #define mp_call_function_n_kw(fun, n_args, n_kw, args) \
184     (mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args))
185 
186 #define mp_arg_check_num(n_args, n_kw, n_args_min, n_args_max, takes_kw) \
187     (mp_fun_table.arg_check_num_sig((n_args), (n_kw), MP_OBJ_FUN_MAKE_SIG((n_args_min), (n_args_max), (takes_kw))))
188 
189 #define MP_DYNRUNTIME_INIT_ENTRY \
190     mp_obj_t old_globals = mp_fun_table.swap_globals(self->globals); \
191     mp_raw_code_t rc; \
192     rc.kind = MP_CODE_NATIVE_VIPER; \
193     rc.scope_flags = 0; \
194     rc.const_table = (void *)self->const_table; \
195     (void)rc;
196 
197 #define MP_DYNRUNTIME_INIT_EXIT \
198     mp_fun_table.swap_globals(old_globals); \
199     return mp_const_none;
200 
201 #define MP_DYNRUNTIME_MAKE_FUNCTION(f) \
202     (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL))
203 
204 #define mp_import_name(name, fromlist, level) \
205     (mp_fun_table.import_name((name), (fromlist), (level)))
206 #define mp_import_from(module, name) \
207     (mp_fun_table.import_from((module), (name)))
208 #define mp_import_all(module) \
209     (mp_fun_table.import_all((module))
210 
211 /******************************************************************************/
212 // Exceptions
213 
214 #define mp_obj_new_exception(o)                 ((mp_obj_t)(o)) // Assumes returned object will be raised, will create instance then
215 #define mp_obj_new_exception_arg1(e_type, arg)  (mp_obj_new_exception_arg1_dyn((e_type), (arg)))
216 
217 #define nlr_raise(o)                            (mp_raise_dyn(o))
218 #define mp_raise_type_arg(type, arg)            (mp_raise_dyn(mp_obj_new_exception_arg1_dyn((type), (arg))))
219 #define mp_raise_msg(type, msg)                 (mp_fun_table.raise_msg((type), (msg)))
220 #define mp_raise_OSError(er)                    (mp_raise_OSError_dyn(er))
221 #define mp_raise_NotImplementedError(msg)       (mp_raise_msg(&mp_type_NotImplementedError, (msg)))
222 #define mp_raise_TypeError(msg)                 (mp_raise_msg(&mp_type_TypeError, (msg)))
223 #define mp_raise_ValueError(msg)                (mp_raise_msg(&mp_type_ValueError, (msg)))
224 
mp_obj_new_exception_arg1_dyn(const mp_obj_type_t * exc_type,mp_obj_t arg)225 static inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_type, mp_obj_t arg) {
226     mp_obj_t args[1] = { arg };
227     return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]);
228 }
229 
mp_raise_dyn(mp_obj_t o)230 static NORETURN inline void mp_raise_dyn(mp_obj_t o) {
231     mp_fun_table.raise(o);
232     for (;;) {
233     }
234 }
235 
mp_raise_OSError_dyn(int er)236 static inline void mp_raise_OSError_dyn(int er) {
237     mp_obj_t args[1] = { MP_OBJ_NEW_SMALL_INT(er) };
238     nlr_raise(mp_call_function_n_kw(mp_load_global(MP_QSTR_OSError), 1, 0, &args[0]));
239 }
240 
241 /******************************************************************************/
242 // Floating point
243 
244 #define mp_obj_new_float_from_f(f)  (mp_fun_table.obj_new_float_from_f((f)))
245 #define mp_obj_new_float_from_d(d)  (mp_fun_table.obj_new_float_from_d((d)))
246 #define mp_obj_get_float_to_f(o)    (mp_fun_table.obj_get_float_to_f((o)))
247 #define mp_obj_get_float_to_d(o)    (mp_fun_table.obj_get_float_to_d((o)))
248 
249 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
250 #define mp_obj_new_float(f)         (mp_obj_new_float_from_f((f)))
251 #define mp_obj_get_float(o)         (mp_obj_get_float_to_f((o)))
252 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
253 #define mp_obj_new_float(f)         (mp_obj_new_float_from_d((f)))
254 #define mp_obj_get_float(o)         (mp_obj_get_float_to_d((o)))
255 #endif
256 
257 /******************************************************************************/
258 // Inline function definitions.
259 
260 // *items may point inside a GC block
mp_obj_get_array_dyn(mp_obj_t o,size_t * len,mp_obj_t ** items)261 static inline void mp_obj_get_array_dyn(mp_obj_t o, size_t *len, mp_obj_t **items) {
262     const mp_obj_type_t *type = mp_obj_get_type(o);
263     if (type == &mp_type_tuple) {
264         mp_obj_tuple_t *t = MP_OBJ_TO_PTR(o);
265         *len = t->len;
266         *items = &t->items[0];
267     } else if (type == &mp_type_list) {
268         mp_obj_list_t *l = MP_OBJ_TO_PTR(o);
269         *len = l->len;
270         *items = l->items;
271     } else {
272         mp_raise_TypeError("expected tuple/list");
273     }
274 }
275 
276 #endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H
277