blob: dc084e159c9e912c6fb34ffba938c252fea699d3 [file] [log] [blame]
Damien George2326d522014-03-27 23:26:35 +00001// This code glues the code emitters to the runtime.
2
Damien George440f0412014-03-28 18:38:20 +00003#include <stdio.h>
Damien Georged1e443d2014-03-29 11:39:36 +00004#include <string.h>
Damien George2326d522014-03-27 23:26:35 +00005#include <assert.h>
6
7#include "misc.h"
8#include "mpconfig.h"
9#include "qstr.h"
10#include "obj.h"
11#include "runtime0.h"
12#include "runtime.h"
13#include "emitglue.h"
Damien George440f0412014-03-28 18:38:20 +000014#include "bc.h"
Damien George2326d522014-03-27 23:26:35 +000015
16#if 0 // print debugging info
17#define DEBUG_PRINT (1)
18#define WRITE_CODE (1)
19#define DEBUG_printf DEBUG_printf
20#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)
21#else // don't print debugging info
22#define DEBUG_printf(...) (void)0
23#define DEBUG_OP_printf(...) (void)0
24#endif
25
26typedef enum {
Damien Georged1e443d2014-03-29 11:39:36 +000027 MP_CODE_UNUSED,
28 MP_CODE_RESERVED,
Damien George2326d522014-03-27 23:26:35 +000029 MP_CODE_BYTE,
30 MP_CODE_NATIVE,
31 MP_CODE_INLINE_ASM,
32} mp_code_kind_t;
33
34typedef struct _mp_code_t {
35 mp_code_kind_t kind : 8;
36 uint scope_flags : 8;
37 uint n_args : 16;
38 union {
39 struct {
40 byte *code;
41 uint len;
42 } u_byte;
43 struct {
44 mp_fun_t fun;
45 } u_native;
46 struct {
47 void *fun;
48 } u_inline_asm;
49 };
50 qstr *arg_names;
51} mp_code_t;
52
53STATIC machine_uint_t unique_codes_alloc = 0;
Damien Georged1e443d2014-03-29 11:39:36 +000054STATIC machine_uint_t unique_codes_total = 0; // always >= unique_codes_alloc
Damien George2326d522014-03-27 23:26:35 +000055STATIC mp_code_t *unique_codes = NULL;
Damien George2326d522014-03-27 23:26:35 +000056
Damien George440f0412014-03-28 18:38:20 +000057#ifdef WRITE_CODE
58FILE *fp_write_code = NULL;
59#endif
60
Damien George2326d522014-03-27 23:26:35 +000061void mp_emit_glue_init(void) {
Damien George2326d522014-03-27 23:26:35 +000062 unique_codes_alloc = 0;
Damien Georged1e443d2014-03-29 11:39:36 +000063 unique_codes_total = 0;
Damien George2326d522014-03-27 23:26:35 +000064 unique_codes = NULL;
Damien George440f0412014-03-28 18:38:20 +000065
66#ifdef WRITE_CODE
67 fp_write_code = fopen("out-code", "wb");
68#endif
Damien George2326d522014-03-27 23:26:35 +000069}
70
71void mp_emit_glue_deinit(void) {
Damien George440f0412014-03-28 18:38:20 +000072#ifdef WRITE_CODE
73 if (fp_write_code != NULL) {
74 fclose(fp_write_code);
75 }
76#endif
77
Damien George2326d522014-03-27 23:26:35 +000078 m_del(mp_code_t, unique_codes, unique_codes_alloc);
79}
80
81uint mp_emit_glue_get_unique_code_id(void) {
Damien Georged1e443d2014-03-29 11:39:36 +000082 // look for an existing unused slot
83 for (uint i = 0; i < unique_codes_alloc; i++) {
84 if (unique_codes[i].kind == MP_CODE_UNUSED) {
85 unique_codes[i].kind = MP_CODE_RESERVED;
86 return i;
87 }
88 }
89 // no existing slot
90 // return next available id, memory will be allocated later
91 return unique_codes_total++;
Damien George2326d522014-03-27 23:26:35 +000092}
93
94STATIC void mp_emit_glue_alloc_unique_codes(void) {
Damien Georged1e443d2014-03-29 11:39:36 +000095 if (unique_codes_total > unique_codes_alloc) {
96 DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, unique_codes_total);
97 // increase size of unique_codes table (all new entries are already reserved)
98 unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, unique_codes_total);
99 for (uint i = unique_codes_alloc; i < unique_codes_total; i++) {
100 unique_codes[i].kind = MP_CODE_RESERVED;
Damien George2326d522014-03-27 23:26:35 +0000101 }
Damien Georged1e443d2014-03-29 11:39:36 +0000102 unique_codes_alloc = unique_codes_total;
Damien George2326d522014-03-27 23:26:35 +0000103 }
104}
105
106void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
107 mp_emit_glue_alloc_unique_codes();
108
Damien Georged1e443d2014-03-29 11:39:36 +0000109 assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
Damien George2326d522014-03-27 23:26:35 +0000110 unique_codes[unique_code_id].kind = MP_CODE_BYTE;
111 unique_codes[unique_code_id].scope_flags = scope_flags;
112 unique_codes[unique_code_id].n_args = n_args;
113 unique_codes[unique_code_id].u_byte.code = code;
114 unique_codes[unique_code_id].u_byte.len = len;
115 unique_codes[unique_code_id].arg_names = arg_names;
116
117 //printf("byte code: %d bytes\n", len);
118
119#ifdef DEBUG_PRINT
120 DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d n_locals=%d\n", unique_code_id, code, len, n_args, n_locals);
121 for (int i = 0; i < 128 && i < len; i++) {
122 if (i > 0 && i % 16 == 0) {
123 DEBUG_printf("\n");
124 }
125 DEBUG_printf(" %02x", code[i]);
126 }
127 DEBUG_printf("\n");
128#if MICROPY_DEBUG_PRINTERS
129 mp_byte_code_print(code, len);
130#endif
131#endif
132}
133
134void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
135 mp_emit_glue_alloc_unique_codes();
136
Damien Georged1e443d2014-03-29 11:39:36 +0000137 assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
Damien George2326d522014-03-27 23:26:35 +0000138 unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
139 unique_codes[unique_code_id].scope_flags = 0;
140 unique_codes[unique_code_id].n_args = n_args;
141 unique_codes[unique_code_id].u_native.fun = fun;
142
143 //printf("native code: %d bytes\n", len);
144
145#ifdef DEBUG_PRINT
146 DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
147 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
148 for (int i = 0; i < 128 && i < len; i++) {
149 if (i > 0 && i % 16 == 0) {
150 DEBUG_printf("\n");
151 }
152 DEBUG_printf(" %02x", fun_data[i]);
153 }
154 DEBUG_printf("\n");
155
156#ifdef WRITE_CODE
157 if (fp_write_code != NULL) {
158 fwrite(fun_data, len, 1, fp_write_code);
159 fflush(fp_write_code);
160 }
161#endif
162#endif
163}
164
165void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
166 mp_emit_glue_alloc_unique_codes();
167
Damien Georged1e443d2014-03-29 11:39:36 +0000168 assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
Damien George2326d522014-03-27 23:26:35 +0000169 unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
170 unique_codes[unique_code_id].scope_flags = 0;
171 unique_codes[unique_code_id].n_args = n_args;
172 unique_codes[unique_code_id].u_inline_asm.fun = fun;
173
174#ifdef DEBUG_PRINT
175 DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
176 byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
177 for (int i = 0; i < 128 && i < len; i++) {
178 if (i > 0 && i % 16 == 0) {
179 DEBUG_printf("\n");
180 }
181 DEBUG_printf(" %02x", fun_data[i]);
182 }
183 DEBUG_printf("\n");
184
185#ifdef WRITE_CODE
186 if (fp_write_code != NULL) {
187 fwrite(fun_data, len, 1, fp_write_code);
188 }
189#endif
190#endif
191}
192
Damien Georgee337f1e2014-03-31 15:18:37 +0100193mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args, mp_obj_t def_kw_args) {
Damien George2326d522014-03-27 23:26:35 +0000194 DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
Damien Georged1e443d2014-03-29 11:39:36 +0000195 if (unique_code_id >= unique_codes_total) {
Damien George2326d522014-03-27 23:26:35 +0000196 // illegal code id
197 return mp_const_none;
198 }
199
Damien Georgee337f1e2014-03-31 15:18:37 +0100200 // TODO implement default kw args
201 assert(def_kw_args == MP_OBJ_NULL);
202
Damien George2326d522014-03-27 23:26:35 +0000203 // make the function, depending on the code kind
204 mp_code_t *c = &unique_codes[unique_code_id];
205 mp_obj_t fun;
206 switch (c->kind) {
207 case MP_CODE_BYTE:
208 fun = mp_obj_new_fun_bc(c->scope_flags, c->arg_names, c->n_args, def_args, c->u_byte.code);
209 break;
210 case MP_CODE_NATIVE:
Damien Georged17926d2014-03-30 13:35:08 +0100211 fun = mp_make_function_n(c->n_args, c->u_native.fun);
Damien George2326d522014-03-27 23:26:35 +0000212 break;
213 case MP_CODE_INLINE_ASM:
214 fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
215 break;
216 default:
Damien Georged1e443d2014-03-29 11:39:36 +0000217 // code id was never assigned (this should not happen)
Damien George2326d522014-03-27 23:26:35 +0000218 assert(0);
Damien Georged1e443d2014-03-29 11:39:36 +0000219 return mp_const_none;
Damien George2326d522014-03-27 23:26:35 +0000220 }
221
222 // check for generator functions and if so wrap in generator object
223 if ((c->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
224 fun = mp_obj_new_gen_wrap(fun);
225 }
226
Damien Georged1e443d2014-03-29 11:39:36 +0000227 // in some cases we can free the unique_code slot
228 // any dynamically allocade memory is now owned by the fun object
229 if (free_unique_code) {
230 memset(c, 0, sizeof *c); // make sure all pointers are zeroed
231 c->kind = MP_CODE_UNUSED;
232 }
233
Damien George2326d522014-03-27 23:26:35 +0000234 return fun;
235}
236
Damien Georgee337f1e2014-03-31 15:18:37 +0100237mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args) {
Damien George2326d522014-03-27 23:26:35 +0000238 DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
239 // make function object
Damien Georgee337f1e2014-03-31 15:18:37 +0100240 mp_obj_t ffun = mp_make_function_from_id(unique_code_id, false, def_args, def_kw_args);
Damien George2326d522014-03-27 23:26:35 +0000241 // wrap function in closure object
242 return mp_obj_new_closure(ffun, closure_tuple);
243}