blob: ea756d3ee2a5c24a3340733c7c3a129092181588 [file] [log] [blame]
Damien George0699c6b2016-01-31 21:45:22 +00001#!/usr/bin/env python3
2#
3# This file is part of the MicroPython project, http://micropython.org/
4#
5# The MIT License (MIT)
6#
Damien Georgefaf3d3e2019-06-04 22:13:32 +10007# Copyright (c) 2016-2019 Damien P. George
Damien George0699c6b2016-01-31 21:45:22 +00008#
9# Permission is hereby granted, free of charge, to any person obtaining a copy
10# of this software and associated documentation files (the "Software"), to deal
11# in the Software without restriction, including without limitation the rights
12# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13# copies of the Software, and to permit persons to whom the Software is
14# furnished to do so, subject to the following conditions:
15#
16# The above copyright notice and this permission notice shall be included in
17# all copies or substantial portions of the Software.
18#
19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25# THE SOFTWARE.
26
Damien Georgec3beb162016-04-15 11:56:10 +010027# Python 2/3 compatibility code
28from __future__ import print_function
29import platform
Damien George69661f32020-02-27 15:36:53 +110030
31if platform.python_version_tuple()[0] == "2":
Damien Georgec3beb162016-04-15 11:56:10 +010032 str_cons = lambda val, enc=None: val
33 bytes_cons = lambda val, enc=None: bytearray(val)
34 is_str_type = lambda o: type(o) is str
35 is_bytes_type = lambda o: type(o) is bytearray
36 is_int_type = lambda o: type(o) is int or type(o) is long
37else:
38 str_cons = str
39 bytes_cons = bytes
40 is_str_type = lambda o: type(o) is str
41 is_bytes_type = lambda o: type(o) is bytes
42 is_int_type = lambda o: type(o) is int
43# end compatibility code
44
Damien George0699c6b2016-01-31 21:45:22 +000045import sys
Damien George72ae3c72016-08-10 13:26:11 +100046import struct
Damien George0699c6b2016-01-31 21:45:22 +000047from collections import namedtuple
48
Damien George69661f32020-02-27 15:36:53 +110049sys.path.append(sys.path[0] + "/../py")
Damien George0699c6b2016-01-31 21:45:22 +000050import makeqstrdata as qstrutil
51
Damien George69661f32020-02-27 15:36:53 +110052
Damien George0699c6b2016-01-31 21:45:22 +000053class FreezeError(Exception):
54 def __init__(self, rawcode, msg):
55 self.rawcode = rawcode
56 self.msg = msg
57
58 def __str__(self):
Damien George69661f32020-02-27 15:36:53 +110059 return "error while freezing %s: %s" % (self.rawcode.source_file, self.msg)
60
Damien George0699c6b2016-01-31 21:45:22 +000061
62class Config:
Damien George5716c5c2019-09-26 16:39:37 +100063 MPY_VERSION = 5
Damien George0699c6b2016-01-31 21:45:22 +000064 MICROPY_LONGINT_IMPL_NONE = 0
65 MICROPY_LONGINT_IMPL_LONGLONG = 1
66 MICROPY_LONGINT_IMPL_MPZ = 2
Damien George69661f32020-02-27 15:36:53 +110067
68
Damien George0699c6b2016-01-31 21:45:22 +000069config = Config()
70
Damien George69661f32020-02-27 15:36:53 +110071
Damien George4f0931b2019-03-01 14:33:03 +110072class QStrType:
73 def __init__(self, str):
74 self.str = str
75 self.qstr_esc = qstrutil.qstr_escape(self.str)
Damien George69661f32020-02-27 15:36:53 +110076 self.qstr_id = "MP_QSTR_" + self.qstr_esc
77
Damien George4f0931b2019-03-01 14:33:03 +110078
79# Initialise global list of qstrs with static qstrs
Damien George69661f32020-02-27 15:36:53 +110080global_qstrs = [None] # MP_QSTRnull should never be referenced
Damien George4f0931b2019-03-01 14:33:03 +110081for n in qstrutil.static_qstr_list:
82 global_qstrs.append(QStrType(n))
83
Damien George69661f32020-02-27 15:36:53 +110084
Damien George5996eeb2019-02-25 23:15:51 +110085class QStrWindow:
Damien George74ed0682019-04-08 15:20:56 +100086 def __init__(self, size):
Damien George5996eeb2019-02-25 23:15:51 +110087 self.window = []
Damien George74ed0682019-04-08 15:20:56 +100088 self.size = size
Damien George5996eeb2019-02-25 23:15:51 +110089
90 def push(self, val):
Damien George69661f32020-02-27 15:36:53 +110091 self.window = [val] + self.window[: self.size - 1]
Damien George5996eeb2019-02-25 23:15:51 +110092
93 def access(self, idx):
94 val = self.window[idx]
Damien George69661f32020-02-27 15:36:53 +110095 self.window = [val] + self.window[:idx] + self.window[idx + 1 :]
Damien George5996eeb2019-02-25 23:15:51 +110096 return val
97
Damien George69661f32020-02-27 15:36:53 +110098
Damien Georgeea3c80a2019-02-21 15:18:59 +110099MP_CODE_BYTECODE = 2
100MP_CODE_NATIVE_PY = 3
101MP_CODE_NATIVE_VIPER = 4
102MP_CODE_NATIVE_ASM = 5
103
104MP_NATIVE_ARCH_NONE = 0
105MP_NATIVE_ARCH_X86 = 1
106MP_NATIVE_ARCH_X64 = 2
107MP_NATIVE_ARCH_ARMV6 = 3
108MP_NATIVE_ARCH_ARMV6M = 4
109MP_NATIVE_ARCH_ARMV7M = 5
110MP_NATIVE_ARCH_ARMV7EM = 6
111MP_NATIVE_ARCH_ARMV7EMSP = 7
112MP_NATIVE_ARCH_ARMV7EMDP = 8
113MP_NATIVE_ARCH_XTENSA = 9
Damien George9adedce2019-09-13 13:15:12 +1000114MP_NATIVE_ARCH_XTENSAWIN = 10
Damien Georgeea3c80a2019-02-21 15:18:59 +1100115
Damien George69661f32020-02-27 15:36:53 +1100116MP_BC_MASK_EXTRA_BYTE = 0x9E
Damien George0699c6b2016-01-31 21:45:22 +0000117
Damien George1f7202d2019-09-02 21:35:26 +1000118MP_BC_FORMAT_BYTE = 0
119MP_BC_FORMAT_QSTR = 1
120MP_BC_FORMAT_VAR_UINT = 2
121MP_BC_FORMAT_OFFSET = 3
122
Damien George0699c6b2016-01-31 21:45:22 +0000123# extra byte if caching enabled:
Damien George5889cf52019-09-02 20:24:01 +1000124MP_BC_LOAD_NAME = 0x11
125MP_BC_LOAD_GLOBAL = 0x12
126MP_BC_LOAD_ATTR = 0x13
127MP_BC_STORE_ATTR = 0x18
Damien George0699c6b2016-01-31 21:45:22 +0000128
Damien George0699c6b2016-01-31 21:45:22 +0000129# this function mirrors that in py/bc.c
Damien George1f7202d2019-09-02 21:35:26 +1000130def mp_opcode_format(bytecode, ip, count_var_uint):
Damien George0699c6b2016-01-31 21:45:22 +0000131 opcode = bytecode[ip]
132 ip_start = ip
Damien George69661f32020-02-27 15:36:53 +1100133 f = (0x000003A4 >> (2 * ((opcode) >> 4))) & 3
Damien George1f7202d2019-09-02 21:35:26 +1000134 if f == MP_BC_FORMAT_QSTR:
Damien George814d5802018-12-11 00:52:33 +1100135 if config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE:
Damien George69661f32020-02-27 15:36:53 +1100136 if (
137 opcode == MP_BC_LOAD_NAME
Damien George814d5802018-12-11 00:52:33 +1100138 or opcode == MP_BC_LOAD_GLOBAL
139 or opcode == MP_BC_LOAD_ATTR
Damien George69661f32020-02-27 15:36:53 +1100140 or opcode == MP_BC_STORE_ATTR
141 ):
Damien George814d5802018-12-11 00:52:33 +1100142 ip += 1
Damien George0699c6b2016-01-31 21:45:22 +0000143 ip += 3
144 else:
Damien George1f7202d2019-09-02 21:35:26 +1000145 extra_byte = (opcode & MP_BC_MASK_EXTRA_BYTE) == 0
Damien George0699c6b2016-01-31 21:45:22 +0000146 ip += 1
Damien George1f7202d2019-09-02 21:35:26 +1000147 if f == MP_BC_FORMAT_VAR_UINT:
Damien George992a6e12019-03-01 14:03:10 +1100148 if count_var_uint:
149 while bytecode[ip] & 0x80 != 0:
150 ip += 1
Damien George0699c6b2016-01-31 21:45:22 +0000151 ip += 1
Damien George1f7202d2019-09-02 21:35:26 +1000152 elif f == MP_BC_FORMAT_OFFSET:
Damien George0699c6b2016-01-31 21:45:22 +0000153 ip += 2
154 ip += extra_byte
155 return f, ip - ip_start
156
Damien George69661f32020-02-27 15:36:53 +1100157
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000158def read_prelude_sig(read_byte):
159 z = read_byte()
160 # xSSSSEAA
Damien George69661f32020-02-27 15:36:53 +1100161 S = (z >> 3) & 0xF
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000162 E = (z >> 2) & 0x1
163 F = 0
164 A = z & 0x3
165 K = 0
166 D = 0
167 n = 0
168 while z & 0x80:
169 z = read_byte()
170 # xFSSKAED
171 S |= (z & 0x30) << (2 * n)
172 E |= (z & 0x02) << n
173 F |= ((z & 0x40) >> 6) << n
174 A |= (z & 0x4) << n
175 K |= ((z & 0x08) >> 3) << n
176 D |= (z & 0x1) << n
177 n += 1
178 S += 1
179 return S, E, F, A, K, D
180
Damien George69661f32020-02-27 15:36:53 +1100181
Damien Georgec8c0fd42019-09-25 15:45:47 +1000182def read_prelude_size(read_byte):
183 I = 0
184 C = 0
185 n = 0
186 while True:
187 z = read_byte()
188 # xIIIIIIC
Damien George69661f32020-02-27 15:36:53 +1100189 I |= ((z & 0x7E) >> 1) << (6 * n)
Damien Georgec8c0fd42019-09-25 15:45:47 +1000190 C |= (z & 1) << n
191 if not (z & 0x80):
192 break
193 n += 1
194 return I, C
195
Damien George69661f32020-02-27 15:36:53 +1100196
Damien Georgeea3c80a2019-02-21 15:18:59 +1100197def extract_prelude(bytecode, ip):
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000198 def local_read_byte():
199 b = bytecode[ip_ref[0]]
200 ip_ref[0] += 1
201 return b
Damien George69661f32020-02-27 15:36:53 +1100202
203 ip_ref = [ip] # to close over ip in Python 2 and 3
204 (
205 n_state,
206 n_exc_stack,
207 scope_flags,
208 n_pos_args,
209 n_kwonly_args,
210 n_def_pos_args,
211 ) = read_prelude_sig(local_read_byte)
Damien Georgec8c0fd42019-09-25 15:45:47 +1000212 n_info, n_cell = read_prelude_size(local_read_byte)
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000213 ip = ip_ref[0]
214
Damien Georgec8c0fd42019-09-25 15:45:47 +1000215 ip2 = ip
216 ip = ip2 + n_info + n_cell
Damien George0699c6b2016-01-31 21:45:22 +0000217 # ip now points to first opcode
218 # ip2 points to simple_name qstr
Damien Georgec8c0fd42019-09-25 15:45:47 +1000219 return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args)
Damien George0699c6b2016-01-31 21:45:22 +0000220
Damien George69661f32020-02-27 15:36:53 +1100221
Damien Georgeea3c80a2019-02-21 15:18:59 +1100222class MPFunTable:
223 pass
224
Damien George69661f32020-02-27 15:36:53 +1100225
Damien George643d2a02019-04-08 11:21:18 +1000226class RawCode(object):
Damien George02fd83b2016-05-03 12:24:39 +0100227 # a set of all escaped names, to make sure they are unique
228 escaped_names = set()
229
Damien Georgeea3c80a2019-02-21 15:18:59 +1100230 # convert code kind number to string
231 code_kind_str = {
Damien George69661f32020-02-27 15:36:53 +1100232 MP_CODE_BYTECODE: "MP_CODE_BYTECODE",
233 MP_CODE_NATIVE_PY: "MP_CODE_NATIVE_PY",
234 MP_CODE_NATIVE_VIPER: "MP_CODE_NATIVE_VIPER",
235 MP_CODE_NATIVE_ASM: "MP_CODE_NATIVE_ASM",
Damien Georgeea3c80a2019-02-21 15:18:59 +1100236 }
237
238 def __init__(self, code_kind, bytecode, prelude_offset, qstrs, objs, raw_codes):
Damien George0699c6b2016-01-31 21:45:22 +0000239 # set core variables
Damien Georgeea3c80a2019-02-21 15:18:59 +1100240 self.code_kind = code_kind
Damien George0699c6b2016-01-31 21:45:22 +0000241 self.bytecode = bytecode
Damien Georgeea3c80a2019-02-21 15:18:59 +1100242 self.prelude_offset = prelude_offset
Damien George0699c6b2016-01-31 21:45:22 +0000243 self.qstrs = qstrs
244 self.objs = objs
245 self.raw_codes = raw_codes
246
Damien Georgeea3c80a2019-02-21 15:18:59 +1100247 if self.prelude_offset is None:
248 # no prelude, assign a dummy simple_name
249 self.prelude_offset = 0
250 self.simple_name = global_qstrs[1]
251 else:
252 # extract prelude
253 self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode, self.prelude_offset)
254 self.simple_name = self._unpack_qstr(self.ip2)
255 self.source_file = self._unpack_qstr(self.ip2 + 2)
Martin Milata492cf342020-08-13 15:20:08 +0200256 self.line_info_offset = self.ip2 + 4
Damien George0699c6b2016-01-31 21:45:22 +0000257
258 def _unpack_qstr(self, ip):
259 qst = self.bytecode[ip] | self.bytecode[ip + 1] << 8
260 return global_qstrs[qst]
261
262 def dump(self):
263 # dump children first
264 for rc in self.raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100265 rc.freeze("")
Damien George0699c6b2016-01-31 21:45:22 +0000266 # TODO
267
Damien Georgeea3c80a2019-02-21 15:18:59 +1100268 def freeze_children(self, parent_name):
Damien George0699c6b2016-01-31 21:45:22 +0000269 self.escaped_name = parent_name + self.simple_name.qstr_esc
270
Damien George02fd83b2016-05-03 12:24:39 +0100271 # make sure the escaped name is unique
272 i = 2
273 while self.escaped_name in RawCode.escaped_names:
274 self.escaped_name = parent_name + self.simple_name.qstr_esc + str(i)
275 i += 1
276 RawCode.escaped_names.add(self.escaped_name)
277
Damien George0699c6b2016-01-31 21:45:22 +0000278 # emit children first
279 for rc in self.raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100280 rc.freeze(self.escaped_name + "_")
Damien George0699c6b2016-01-31 21:45:22 +0000281
Damien Georgeea3c80a2019-02-21 15:18:59 +1100282 def freeze_constants(self):
Damien George0699c6b2016-01-31 21:45:22 +0000283 # generate constant objects
284 for i, obj in enumerate(self.objs):
Damien George69661f32020-02-27 15:36:53 +1100285 obj_name = "const_obj_%s_%u" % (self.escaped_name, i)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100286 if obj is MPFunTable:
287 pass
288 elif obj is Ellipsis:
Damien George69661f32020-02-27 15:36:53 +1100289 print("#define %s mp_const_ellipsis_obj" % obj_name)
Damien George9ba3de62017-11-15 12:46:08 +1100290 elif is_str_type(obj) or is_bytes_type(obj):
Damien Georgeb6bdf182016-09-02 15:10:45 +1000291 if is_str_type(obj):
Damien George69661f32020-02-27 15:36:53 +1100292 obj = bytes_cons(obj, "utf8")
293 obj_type = "mp_type_str"
Damien Georgeb6bdf182016-09-02 15:10:45 +1000294 else:
Damien George69661f32020-02-27 15:36:53 +1100295 obj_type = "mp_type_bytes"
296 print(
297 'STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};'
298 % (
299 obj_name,
300 obj_type,
301 qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH),
302 len(obj),
303 "".join(("\\x%02x" % b) for b in obj),
304 )
305 )
Damien Georgec3beb162016-04-15 11:56:10 +0100306 elif is_int_type(obj):
Damien George0699c6b2016-01-31 21:45:22 +0000307 if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE:
308 # TODO check if we can actually fit this long-int into a small-int
Damien George69661f32020-02-27 15:36:53 +1100309 raise FreezeError(self, "target does not support long int")
Damien George0699c6b2016-01-31 21:45:22 +0000310 elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG:
311 # TODO
Damien George69661f32020-02-27 15:36:53 +1100312 raise FreezeError(self, "freezing int to long-long is not implemented")
Damien George0699c6b2016-01-31 21:45:22 +0000313 elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ:
314 neg = 0
315 if obj < 0:
316 obj = -obj
317 neg = 1
318 bits_per_dig = config.MPZ_DIG_SIZE
319 digs = []
320 z = obj
321 while z:
322 digs.append(z & ((1 << bits_per_dig) - 1))
323 z >>= bits_per_dig
324 ndigs = len(digs)
Damien George69661f32020-02-27 15:36:53 +1100325 digs = ",".join(("%#x" % d) for d in digs)
326 print(
327 "STATIC const mp_obj_int_t %s = {{&mp_type_int}, "
328 "{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t*)(const uint%u_t[]){%s}}};"
329 % (obj_name, neg, ndigs, ndigs, bits_per_dig, bits_per_dig, digs)
330 )
Damien George0699c6b2016-01-31 21:45:22 +0000331 elif type(obj) is float:
Damien George69661f32020-02-27 15:36:53 +1100332 print(
333 "#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B"
334 )
335 print(
stijnbcf01d12020-03-31 14:48:08 +0200336 "STATIC const mp_obj_float_t %s = {{&mp_type_float}, (mp_float_t)%.16g};"
337 % (obj_name, obj)
Damien George69661f32020-02-27 15:36:53 +1100338 )
339 print("#endif")
Damien Georgec51c8832016-09-03 00:19:02 +1000340 elif type(obj) is complex:
Damien George69661f32020-02-27 15:36:53 +1100341 print(
stijnbcf01d12020-03-31 14:48:08 +0200342 "STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, (mp_float_t)%.16g, (mp_float_t)%.16g};"
Damien George69661f32020-02-27 15:36:53 +1100343 % (obj_name, obj.real, obj.imag)
344 )
Damien George0699c6b2016-01-31 21:45:22 +0000345 else:
Damien George69661f32020-02-27 15:36:53 +1100346 raise FreezeError(self, "freezing of object %r is not implemented" % (obj,))
Damien George0699c6b2016-01-31 21:45:22 +0000347
Damien Georgeb6a32892017-08-12 22:26:18 +1000348 # generate constant table, if it has any entries
349 const_table_len = len(self.qstrs) + len(self.objs) + len(self.raw_codes)
350 if const_table_len:
Damien George69661f32020-02-27 15:36:53 +1100351 print(
352 "STATIC const mp_rom_obj_t const_table_data_%s[%u] = {"
353 % (self.escaped_name, const_table_len)
354 )
Damien Georgeb6a32892017-08-12 22:26:18 +1000355 for qst in self.qstrs:
Damien George69661f32020-02-27 15:36:53 +1100356 print(" MP_ROM_QSTR(%s)," % global_qstrs[qst].qstr_id)
Damien Georgeb6a32892017-08-12 22:26:18 +1000357 for i in range(len(self.objs)):
Damien Georgeea3c80a2019-02-21 15:18:59 +1100358 if self.objs[i] is MPFunTable:
Damien George69661f32020-02-27 15:36:53 +1100359 print(" &mp_fun_table,")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100360 elif type(self.objs[i]) is float:
Damien George69661f32020-02-27 15:36:53 +1100361 print(
362 "#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B"
363 )
364 print(" MP_ROM_PTR(&const_obj_%s_%u)," % (self.escaped_name, i))
365 print("#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C")
366 n = struct.unpack("<I", struct.pack("<f", self.objs[i]))[0]
Damien Georgeb6a32892017-08-12 22:26:18 +1000367 n = ((n & ~0x3) | 2) + 0x80800000
Damien George69661f32020-02-27 15:36:53 +1100368 print(" (mp_rom_obj_t)(0x%08x)," % (n,))
369 print("#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D")
370 n = struct.unpack("<Q", struct.pack("<d", self.objs[i]))[0]
Damien George929d10a2018-07-09 12:22:40 +1000371 n += 0x8004000000000000
Damien George69661f32020-02-27 15:36:53 +1100372 print(" (mp_rom_obj_t)(0x%016x)," % (n,))
373 print("#endif")
Damien Georgeb6a32892017-08-12 22:26:18 +1000374 else:
Damien George69661f32020-02-27 15:36:53 +1100375 print(" MP_ROM_PTR(&const_obj_%s_%u)," % (self.escaped_name, i))
Damien Georgeb6a32892017-08-12 22:26:18 +1000376 for rc in self.raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100377 print(" MP_ROM_PTR(&raw_code_%s)," % rc.escaped_name)
378 print("};")
Damien George0699c6b2016-01-31 21:45:22 +0000379
Damien Georgeea3c80a2019-02-21 15:18:59 +1100380 def freeze_module(self, qstr_links=(), type_sig=0):
Damien George0699c6b2016-01-31 21:45:22 +0000381 # generate module
Damien George69661f32020-02-27 15:36:53 +1100382 if self.simple_name.str != "<module>":
383 print("STATIC ", end="")
384 print("const mp_raw_code_t raw_code_%s = {" % self.escaped_name)
385 print(" .kind = %s," % RawCode.code_kind_str[self.code_kind])
386 print(" .scope_flags = 0x%02x," % self.prelude[2])
387 print(" .n_pos_args = %u," % self.prelude[3])
388 print(" .fun_data = fun_data_%s," % self.escaped_name)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100389 if len(self.qstrs) + len(self.objs) + len(self.raw_codes):
Damien George69661f32020-02-27 15:36:53 +1100390 print(" .const_table = (mp_uint_t*)const_table_data_%s," % self.escaped_name)
Damien Georgeb6a32892017-08-12 22:26:18 +1000391 else:
Damien George69661f32020-02-27 15:36:53 +1100392 print(" .const_table = NULL,")
393 print(" #if MICROPY_PERSISTENT_CODE_SAVE")
394 print(" .fun_data_len = %u," % len(self.bytecode))
395 print(" .n_obj = %u," % len(self.objs))
396 print(" .n_raw_code = %u," % len(self.raw_codes))
Damien Georgec69f58e2019-09-06 23:55:15 +1000397 if self.code_kind == MP_CODE_BYTECODE:
Damien George69661f32020-02-27 15:36:53 +1100398 print(" #if MICROPY_PY_SYS_SETTRACE")
399 print(" .prelude = {")
400 print(" .n_state = %u," % self.prelude[0])
401 print(" .n_exc_stack = %u," % self.prelude[1])
402 print(" .scope_flags = %u," % self.prelude[2])
403 print(" .n_pos_args = %u," % self.prelude[3])
404 print(" .n_kwonly_args = %u," % self.prelude[4])
405 print(" .n_def_pos_args = %u," % self.prelude[5])
406 print(" .qstr_block_name = %s," % self.simple_name.qstr_id)
407 print(" .qstr_source_file = %s," % self.source_file.qstr_id)
Martin Milata492cf342020-08-13 15:20:08 +0200408 print(
409 " .line_info = fun_data_%s + %u,"
410 % (self.escaped_name, self.line_info_offset)
411 )
Damien George69661f32020-02-27 15:36:53 +1100412 print(" .opcodes = fun_data_%s + %u," % (self.escaped_name, self.ip))
413 print(" },")
414 print(" .line_of_definition = %u," % 0) # TODO
415 print(" #endif")
416 print(" #if MICROPY_EMIT_MACHINE_CODE")
417 print(" .prelude_offset = %u," % self.prelude_offset)
418 print(" .n_qstr = %u," % len(qstr_links))
419 print(" .qstr_link = NULL,") # TODO
420 print(" #endif")
421 print(" #endif")
422 print(" #if MICROPY_EMIT_MACHINE_CODE")
423 print(" .type_sig = %u," % type_sig)
424 print(" #endif")
425 print("};")
426
Damien George0699c6b2016-01-31 21:45:22 +0000427
Damien Georgeea3c80a2019-02-21 15:18:59 +1100428class RawCodeBytecode(RawCode):
429 def __init__(self, bytecode, qstrs, objs, raw_codes):
Damien George69661f32020-02-27 15:36:53 +1100430 super(RawCodeBytecode, self).__init__(
431 MP_CODE_BYTECODE, bytecode, 0, qstrs, objs, raw_codes
432 )
Damien Georgeea3c80a2019-02-21 15:18:59 +1100433
434 def freeze(self, parent_name):
435 self.freeze_children(parent_name)
436
437 # generate bytecode data
438 print()
Damien George69661f32020-02-27 15:36:53 +1100439 print(
440 "// frozen bytecode for file %s, scope %s%s"
441 % (self.source_file.str, parent_name, self.simple_name.str)
442 )
443 print("STATIC ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100444 if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE:
Damien George69661f32020-02-27 15:36:53 +1100445 print("const ", end="")
446 print("byte fun_data_%s[%u] = {" % (self.escaped_name, len(self.bytecode)))
447 print(" ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100448 for i in range(self.ip2):
Damien George69661f32020-02-27 15:36:53 +1100449 print(" 0x%02x," % self.bytecode[i], end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100450 print()
Damien George69661f32020-02-27 15:36:53 +1100451 print(" ", self.simple_name.qstr_id, "& 0xff,", self.simple_name.qstr_id, ">> 8,")
452 print(" ", self.source_file.qstr_id, "& 0xff,", self.source_file.qstr_id, ">> 8,")
453 print(" ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100454 for i in range(self.ip2 + 4, self.ip):
Damien George69661f32020-02-27 15:36:53 +1100455 print(" 0x%02x," % self.bytecode[i], end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100456 print()
457 ip = self.ip
458 while ip < len(self.bytecode):
459 f, sz = mp_opcode_format(self.bytecode, ip, True)
460 if f == 1:
461 qst = self._unpack_qstr(ip + 1).qstr_id
Damien George69661f32020-02-27 15:36:53 +1100462 extra = "" if sz == 3 else " 0x%02x," % self.bytecode[ip + 3]
463 print(" ", "0x%02x," % self.bytecode[ip], qst, "& 0xff,", qst, ">> 8,", extra)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100464 else:
Damien George69661f32020-02-27 15:36:53 +1100465 print(" ", "".join("0x%02x, " % self.bytecode[ip + i] for i in range(sz)))
Damien Georgeea3c80a2019-02-21 15:18:59 +1100466 ip += sz
Damien George69661f32020-02-27 15:36:53 +1100467 print("};")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100468
469 self.freeze_constants()
470 self.freeze_module()
471
Damien George69661f32020-02-27 15:36:53 +1100472
Damien Georgeea3c80a2019-02-21 15:18:59 +1100473class RawCodeNative(RawCode):
Damien George69661f32020-02-27 15:36:53 +1100474 def __init__(
475 self,
476 code_kind,
477 fun_data,
478 prelude_offset,
479 prelude,
480 qstr_links,
481 qstrs,
482 objs,
483 raw_codes,
484 type_sig,
485 ):
486 super(RawCodeNative, self).__init__(
487 code_kind, fun_data, prelude_offset, qstrs, objs, raw_codes
488 )
Damien Georgeea3c80a2019-02-21 15:18:59 +1100489 self.prelude = prelude
490 self.qstr_links = qstr_links
491 self.type_sig = type_sig
Damien George69661f32020-02-27 15:36:53 +1100492 if config.native_arch in (
493 MP_NATIVE_ARCH_X86,
494 MP_NATIVE_ARCH_X64,
495 MP_NATIVE_ARCH_XTENSA,
496 MP_NATIVE_ARCH_XTENSAWIN,
497 ):
Damien Georgeea3c80a2019-02-21 15:18:59 +1100498 self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))'
499 else:
500 self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))'
501
Damien George7f24c292019-11-28 13:11:51 +1100502 # Allow single-byte alignment by default for x86/x64.
503 # ARM needs word alignment, ARM Thumb needs halfword, due to instruction size.
504 # Xtensa needs word alignment due to the 32-bit constant table embedded in the code.
Damien George69661f32020-02-27 15:36:53 +1100505 if config.native_arch in (
506 MP_NATIVE_ARCH_ARMV6,
507 MP_NATIVE_ARCH_XTENSA,
508 MP_NATIVE_ARCH_XTENSAWIN,
509 ):
Damien George7f24c292019-11-28 13:11:51 +1100510 # ARMV6 or Xtensa -- four byte align.
Damien George69661f32020-02-27 15:36:53 +1100511 self.fun_data_attributes += " __attribute__ ((aligned (4)))"
Jim Mussared4ab51562019-08-17 00:32:04 +1000512 elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP:
513 # ARMVxxM -- two byte align.
Damien George69661f32020-02-27 15:36:53 +1100514 self.fun_data_attributes += " __attribute__ ((aligned (2)))"
Jim Mussared4ab51562019-08-17 00:32:04 +1000515
Damien Georgeea3c80a2019-02-21 15:18:59 +1100516 def _asm_thumb_rewrite_mov(self, pc, val):
Damien George69661f32020-02-27 15:36:53 +1100517 print(" (%u & 0xf0) | (%s >> 12)," % (self.bytecode[pc], val), end="")
518 print(" (%u & 0xfb) | (%s >> 9 & 0x04)," % (self.bytecode[pc + 1], val), end="")
519 print(" (%s & 0xff)," % (val,), end="")
520 print(" (%u & 0x07) | (%s >> 4 & 0x70)," % (self.bytecode[pc + 3], val))
Damien Georgeea3c80a2019-02-21 15:18:59 +1100521
522 def _link_qstr(self, pc, kind, qst):
523 if kind == 0:
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000524 # Generic 16-bit link
Damien George69661f32020-02-27 15:36:53 +1100525 print(" %s & 0xff, %s >> 8," % (qst, qst))
Damien George9d3031c2019-06-11 11:36:39 +1000526 return 2
Damien Georgeea3c80a2019-02-21 15:18:59 +1100527 else:
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000528 # Architecture-specific link
529 is_obj = kind == 2
530 if is_obj:
Damien George69661f32020-02-27 15:36:53 +1100531 qst = "((uintptr_t)MP_OBJ_NEW_QSTR(%s))" % qst
Damien George7f24c292019-11-28 13:11:51 +1100532 if config.native_arch in (
Damien George69661f32020-02-27 15:36:53 +1100533 MP_NATIVE_ARCH_X86,
534 MP_NATIVE_ARCH_X64,
535 MP_NATIVE_ARCH_XTENSA,
536 MP_NATIVE_ARCH_XTENSAWIN,
537 ):
538 print(
539 " %s & 0xff, (%s >> 8) & 0xff, (%s >> 16) & 0xff, %s >> 24,"
540 % (qst, qst, qst, qst)
541 )
Damien George9d3031c2019-06-11 11:36:39 +1000542 return 4
Damien Georgeea3c80a2019-02-21 15:18:59 +1100543 elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP:
544 if is_obj:
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000545 # qstr object, movw and movt
546 self._asm_thumb_rewrite_mov(pc, qst)
Damien George69661f32020-02-27 15:36:53 +1100547 self._asm_thumb_rewrite_mov(pc + 4, "(%s >> 16)" % qst)
Damien George9d3031c2019-06-11 11:36:39 +1000548 return 8
Damien Georgeea3c80a2019-02-21 15:18:59 +1100549 else:
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000550 # qstr number, movw instruction
551 self._asm_thumb_rewrite_mov(pc, qst)
Damien George9d3031c2019-06-11 11:36:39 +1000552 return 4
Damien Georgeea3c80a2019-02-21 15:18:59 +1100553 else:
554 assert 0
555
556 def freeze(self, parent_name):
Damien George69661f32020-02-27 15:36:53 +1100557 if self.prelude[2] & ~0x0F:
558 raise FreezeError("unable to freeze code with relocations")
Damien Georgefc97d6d2019-12-10 14:57:12 +1100559
Damien Georgeea3c80a2019-02-21 15:18:59 +1100560 self.freeze_children(parent_name)
561
562 # generate native code data
563 print()
564 if self.code_kind == MP_CODE_NATIVE_PY:
Damien George69661f32020-02-27 15:36:53 +1100565 print(
566 "// frozen native code for file %s, scope %s%s"
567 % (self.source_file.str, parent_name, self.simple_name.str)
568 )
Damien Georgeea3c80a2019-02-21 15:18:59 +1100569 elif self.code_kind == MP_CODE_NATIVE_VIPER:
Damien George69661f32020-02-27 15:36:53 +1100570 print("// frozen viper code for scope %s" % (parent_name,))
Damien Georgeea3c80a2019-02-21 15:18:59 +1100571 else:
Damien George69661f32020-02-27 15:36:53 +1100572 print("// frozen assembler code for scope %s" % (parent_name,))
573 print(
574 "STATIC const byte fun_data_%s[%u] %s = {"
575 % (self.escaped_name, len(self.bytecode), self.fun_data_attributes)
576 )
Damien Georgeea3c80a2019-02-21 15:18:59 +1100577
578 if self.code_kind == MP_CODE_NATIVE_PY:
579 i_top = self.prelude_offset
580 else:
581 i_top = len(self.bytecode)
582 i = 0
583 qi = 0
584 while i < i_top:
585 if qi < len(self.qstr_links) and i == self.qstr_links[qi][0]:
586 # link qstr
587 qi_off, qi_kind, qi_val = self.qstr_links[qi]
588 qst = global_qstrs[qi_val].qstr_id
Damien George9d3031c2019-06-11 11:36:39 +1000589 i += self._link_qstr(i, qi_kind, qst)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100590 qi += 1
591 else:
592 # copy machine code (max 16 bytes)
593 i16 = min(i + 16, i_top)
594 if qi < len(self.qstr_links):
595 i16 = min(i16, self.qstr_links[qi][0])
Damien George69661f32020-02-27 15:36:53 +1100596 print(" ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100597 for ii in range(i, i16):
Damien George69661f32020-02-27 15:36:53 +1100598 print(" 0x%02x," % self.bytecode[ii], end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100599 print()
600 i = i16
601
602 if self.code_kind == MP_CODE_NATIVE_PY:
Damien George69661f32020-02-27 15:36:53 +1100603 print(" ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100604 for i in range(self.prelude_offset, self.ip2):
Damien George69661f32020-02-27 15:36:53 +1100605 print(" 0x%02x," % self.bytecode[i], end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100606 print()
607
Damien George69661f32020-02-27 15:36:53 +1100608 print(" ", self.simple_name.qstr_id, "& 0xff,", self.simple_name.qstr_id, ">> 8,")
609 print(" ", self.source_file.qstr_id, "& 0xff,", self.source_file.qstr_id, ">> 8,")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100610
Damien George69661f32020-02-27 15:36:53 +1100611 print(" ", end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100612 for i in range(self.ip2 + 4, self.ip):
Damien George69661f32020-02-27 15:36:53 +1100613 print(" 0x%02x," % self.bytecode[i], end="")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100614 print()
615
Damien George69661f32020-02-27 15:36:53 +1100616 print("};")
Damien Georgeea3c80a2019-02-21 15:18:59 +1100617
618 self.freeze_constants()
619 self.freeze_module(self.qstr_links, self.type_sig)
620
Damien George69661f32020-02-27 15:36:53 +1100621
Damien George992a6e12019-03-01 14:03:10 +1100622class BytecodeBuffer:
623 def __init__(self, size):
624 self.buf = bytearray(size)
625 self.idx = 0
626
627 def is_full(self):
628 return self.idx == len(self.buf)
629
630 def append(self, b):
631 self.buf[self.idx] = b
632 self.idx += 1
633
Damien George69661f32020-02-27 15:36:53 +1100634
Damien George992a6e12019-03-01 14:03:10 +1100635def read_byte(f, out=None):
636 b = bytes_cons(f.read(1))[0]
637 if out is not None:
638 out.append(b)
639 return b
640
Damien George69661f32020-02-27 15:36:53 +1100641
Damien George992a6e12019-03-01 14:03:10 +1100642def read_uint(f, out=None):
Damien George0699c6b2016-01-31 21:45:22 +0000643 i = 0
644 while True:
Damien George992a6e12019-03-01 14:03:10 +1100645 b = read_byte(f, out)
Damien George69661f32020-02-27 15:36:53 +1100646 i = (i << 7) | (b & 0x7F)
Damien George0699c6b2016-01-31 21:45:22 +0000647 if b & 0x80 == 0:
648 break
649 return i
650
Damien George69661f32020-02-27 15:36:53 +1100651
Damien George5996eeb2019-02-25 23:15:51 +1100652def read_qstr(f, qstr_win):
Damien George0699c6b2016-01-31 21:45:22 +0000653 ln = read_uint(f)
Damien George4f0931b2019-03-01 14:33:03 +1100654 if ln == 0:
655 # static qstr
656 return bytes_cons(f.read(1))[0]
Damien George5996eeb2019-02-25 23:15:51 +1100657 if ln & 1:
658 # qstr in table
659 return qstr_win.access(ln >> 1)
660 ln >>= 1
Damien George69661f32020-02-27 15:36:53 +1100661 data = str_cons(f.read(ln), "utf8")
Damien George4f0931b2019-03-01 14:33:03 +1100662 global_qstrs.append(QStrType(data))
Damien George5996eeb2019-02-25 23:15:51 +1100663 qstr_win.push(len(global_qstrs) - 1)
Damien George0699c6b2016-01-31 21:45:22 +0000664 return len(global_qstrs) - 1
665
Damien George69661f32020-02-27 15:36:53 +1100666
Damien George0699c6b2016-01-31 21:45:22 +0000667def read_obj(f):
668 obj_type = f.read(1)
Damien George69661f32020-02-27 15:36:53 +1100669 if obj_type == b"e":
Damien George0699c6b2016-01-31 21:45:22 +0000670 return Ellipsis
671 else:
672 buf = f.read(read_uint(f))
Damien George69661f32020-02-27 15:36:53 +1100673 if obj_type == b"s":
674 return str_cons(buf, "utf8")
675 elif obj_type == b"b":
Damien Georgec3beb162016-04-15 11:56:10 +0100676 return bytes_cons(buf)
Damien George69661f32020-02-27 15:36:53 +1100677 elif obj_type == b"i":
678 return int(str_cons(buf, "ascii"), 10)
679 elif obj_type == b"f":
680 return float(str_cons(buf, "ascii"))
681 elif obj_type == b"c":
682 return complex(str_cons(buf, "ascii"))
Damien George0699c6b2016-01-31 21:45:22 +0000683 else:
684 assert 0
685
Damien George69661f32020-02-27 15:36:53 +1100686
Damien George23f06912019-10-10 15:30:16 +1100687def read_prelude(f, bytecode, qstr_win):
Damien George69661f32020-02-27 15:36:53 +1100688 (
689 n_state,
690 n_exc_stack,
691 scope_flags,
692 n_pos_args,
693 n_kwonly_args,
694 n_def_pos_args,
695 ) = read_prelude_sig(lambda: read_byte(f, bytecode))
Damien Georgec8c0fd42019-09-25 15:45:47 +1000696 n_info, n_cell = read_prelude_size(lambda: read_byte(f, bytecode))
Damien George69661f32020-02-27 15:36:53 +1100697 read_qstr_and_pack(f, bytecode, qstr_win) # simple_name
698 read_qstr_and_pack(f, bytecode, qstr_win) # source_file
Damien George23f06912019-10-10 15:30:16 +1100699 for _ in range(n_info - 4 + n_cell):
Damien George992a6e12019-03-01 14:03:10 +1100700 read_byte(f, bytecode)
Damien George23f06912019-10-10 15:30:16 +1100701 return n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args
Damien George0699c6b2016-01-31 21:45:22 +0000702
Damien George69661f32020-02-27 15:36:53 +1100703
Damien George992a6e12019-03-01 14:03:10 +1100704def read_qstr_and_pack(f, bytecode, qstr_win):
705 qst = read_qstr(f, qstr_win)
Damien George69661f32020-02-27 15:36:53 +1100706 bytecode.append(qst & 0xFF)
Damien George992a6e12019-03-01 14:03:10 +1100707 bytecode.append(qst >> 8)
708
Damien George69661f32020-02-27 15:36:53 +1100709
Damien George992a6e12019-03-01 14:03:10 +1100710def read_bytecode(file, bytecode, qstr_win):
711 while not bytecode.is_full():
712 op = read_byte(file, bytecode)
713 f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False)
714 sz -= 1
Damien George1f7202d2019-09-02 21:35:26 +1000715 if f == MP_BC_FORMAT_QSTR:
Damien George992a6e12019-03-01 14:03:10 +1100716 read_qstr_and_pack(file, bytecode, qstr_win)
717 sz -= 2
Damien George1f7202d2019-09-02 21:35:26 +1000718 elif f == MP_BC_FORMAT_VAR_UINT:
Damien George992a6e12019-03-01 14:03:10 +1100719 while read_byte(file, bytecode) & 0x80:
720 pass
721 for _ in range(sz):
722 read_byte(file, bytecode)
Damien George0699c6b2016-01-31 21:45:22 +0000723
Damien George69661f32020-02-27 15:36:53 +1100724
Damien George5996eeb2019-02-25 23:15:51 +1100725def read_raw_code(f, qstr_win):
Damien Georgeea3c80a2019-02-21 15:18:59 +1100726 kind_len = read_uint(f)
727 kind = (kind_len & 3) + MP_CODE_BYTECODE
728 fun_data_len = kind_len >> 2
729 fun_data = BytecodeBuffer(fun_data_len)
730
731 if kind == MP_CODE_BYTECODE:
Damien George23f06912019-10-10 15:30:16 +1100732 prelude = read_prelude(f, fun_data, qstr_win)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100733 read_bytecode(f, fun_data, qstr_win)
734 else:
735 fun_data.buf[:] = f.read(fun_data_len)
736
737 qstr_links = []
738 if kind in (MP_CODE_NATIVE_PY, MP_CODE_NATIVE_VIPER):
739 # load qstr link table
740 n_qstr_link = read_uint(f)
741 for _ in range(n_qstr_link):
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000742 off = read_uint(f)
Damien Georgeea3c80a2019-02-21 15:18:59 +1100743 qst = read_qstr(f, qstr_win)
744 qstr_links.append((off >> 2, off & 3, qst))
745
746 type_sig = 0
747 if kind == MP_CODE_NATIVE_PY:
748 prelude_offset = read_uint(f)
749 _, name_idx, prelude = extract_prelude(fun_data.buf, prelude_offset)
Damien George69661f32020-02-27 15:36:53 +1100750 fun_data.idx = name_idx # rewind to where qstrs are in prelude
751 read_qstr_and_pack(f, fun_data, qstr_win) # simple_name
752 read_qstr_and_pack(f, fun_data, qstr_win) # source_file
Damien Georgeea3c80a2019-02-21 15:18:59 +1100753 else:
754 prelude_offset = None
755 scope_flags = read_uint(f)
756 n_pos_args = 0
757 if kind == MP_CODE_NATIVE_ASM:
758 n_pos_args = read_uint(f)
759 type_sig = read_uint(f)
760 prelude = (None, None, scope_flags, n_pos_args, 0)
761
Damien Georgeea3c80a2019-02-21 15:18:59 +1100762 qstrs = []
763 objs = []
764 raw_codes = []
765 if kind != MP_CODE_NATIVE_ASM:
766 # load constant table
767 n_obj = read_uint(f)
768 n_raw_code = read_uint(f)
769 qstrs = [read_qstr(f, qstr_win) for _ in range(prelude[3] + prelude[4])]
770 if kind != MP_CODE_BYTECODE:
771 objs.append(MPFunTable)
772 objs.extend([read_obj(f) for _ in range(n_obj)])
773 raw_codes = [read_raw_code(f, qstr_win) for _ in range(n_raw_code)]
774
775 if kind == MP_CODE_BYTECODE:
776 return RawCodeBytecode(fun_data.buf, qstrs, objs, raw_codes)
777 else:
Damien George69661f32020-02-27 15:36:53 +1100778 return RawCodeNative(
779 kind,
780 fun_data.buf,
781 prelude_offset,
782 prelude,
783 qstr_links,
784 qstrs,
785 objs,
786 raw_codes,
787 type_sig,
788 )
789
Damien George0699c6b2016-01-31 21:45:22 +0000790
791def read_mpy(filename):
Damien George69661f32020-02-27 15:36:53 +1100792 with open(filename, "rb") as f:
Damien Georgec3beb162016-04-15 11:56:10 +0100793 header = bytes_cons(f.read(4))
Damien George69661f32020-02-27 15:36:53 +1100794 if header[0] != ord("M"):
795 raise Exception("not a valid .mpy file")
Damien George6a110482017-02-17 00:19:34 +1100796 if header[1] != config.MPY_VERSION:
Damien George69661f32020-02-27 15:36:53 +1100797 raise Exception("incompatible .mpy version")
Damien George5996eeb2019-02-25 23:15:51 +1100798 feature_byte = header[2]
799 qw_size = read_uint(f)
800 config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0
801 config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0
Damien Georgefaf3d3e2019-06-04 22:13:32 +1000802 mpy_native_arch = feature_byte >> 2
803 if mpy_native_arch != MP_NATIVE_ARCH_NONE:
804 if config.native_arch == MP_NATIVE_ARCH_NONE:
805 config.native_arch = mpy_native_arch
806 elif config.native_arch != mpy_native_arch:
Damien George69661f32020-02-27 15:36:53 +1100807 raise Exception("native architecture mismatch")
Damien George0699c6b2016-01-31 21:45:22 +0000808 config.mp_small_int_bits = header[3]
Damien George5996eeb2019-02-25 23:15:51 +1100809 qstr_win = QStrWindow(qw_size)
Damien George27879842019-10-09 14:23:15 +1100810 rc = read_raw_code(f, qstr_win)
811 rc.mpy_source_file = filename
812 rc.qstr_win_size = qw_size
813 return rc
Damien George0699c6b2016-01-31 21:45:22 +0000814
Damien George69661f32020-02-27 15:36:53 +1100815
Damien George0699c6b2016-01-31 21:45:22 +0000816def dump_mpy(raw_codes):
817 for rc in raw_codes:
818 rc.dump()
819
Damien George69661f32020-02-27 15:36:53 +1100820
Damien Georgeb4790af2016-09-02 15:09:21 +1000821def freeze_mpy(base_qstrs, raw_codes):
Damien George0699c6b2016-01-31 21:45:22 +0000822 # add to qstrs
823 new = {}
824 for q in global_qstrs:
825 # don't add duplicates
Damien George4f0931b2019-03-01 14:33:03 +1100826 if q is None or q.qstr_esc in base_qstrs or q.qstr_esc in new:
Damien George0699c6b2016-01-31 21:45:22 +0000827 continue
828 new[q.qstr_esc] = (len(new), q.qstr_esc, q.str)
829 new = sorted(new.values(), key=lambda x: x[0])
830
831 print('#include "py/mpconfig.h"')
832 print('#include "py/objint.h"')
833 print('#include "py/objstr.h"')
834 print('#include "py/emitglue.h"')
Damien George360d9722019-10-07 11:56:24 +1100835 print('#include "py/nativeglue.h"')
Damien George0699c6b2016-01-31 21:45:22 +0000836 print()
837
Damien George69661f32020-02-27 15:36:53 +1100838 print(
839 "#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u"
840 % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
841 )
Damien George98458a42017-01-05 15:52:52 +1100842 print('#error "incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE"')
Damien George69661f32020-02-27 15:36:53 +1100843 print("#endif")
Damien George99b47192016-05-16 23:13:30 +0100844 print()
845
Damien George69661f32020-02-27 15:36:53 +1100846 print("#if MICROPY_LONGINT_IMPL != %u" % config.MICROPY_LONGINT_IMPL)
Damien George99b47192016-05-16 23:13:30 +0100847 print('#error "incompatible MICROPY_LONGINT_IMPL"')
Damien George69661f32020-02-27 15:36:53 +1100848 print("#endif")
Damien George99b47192016-05-16 23:13:30 +0100849 print()
850
851 if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ:
Damien George69661f32020-02-27 15:36:53 +1100852 print("#if MPZ_DIG_SIZE != %u" % config.MPZ_DIG_SIZE)
Damien George99b47192016-05-16 23:13:30 +0100853 print('#error "incompatible MPZ_DIG_SIZE"')
Damien George69661f32020-02-27 15:36:53 +1100854 print("#endif")
Damien George99b47192016-05-16 23:13:30 +0100855 print()
856
Damien George69661f32020-02-27 15:36:53 +1100857 print("#if MICROPY_PY_BUILTINS_FLOAT")
858 print("typedef struct _mp_obj_float_t {")
859 print(" mp_obj_base_t base;")
860 print(" mp_float_t value;")
861 print("} mp_obj_float_t;")
862 print("#endif")
Damien George0699c6b2016-01-31 21:45:22 +0000863 print()
864
Damien George69661f32020-02-27 15:36:53 +1100865 print("#if MICROPY_PY_BUILTINS_COMPLEX")
866 print("typedef struct _mp_obj_complex_t {")
867 print(" mp_obj_base_t base;")
868 print(" mp_float_t real;")
869 print(" mp_float_t imag;")
870 print("} mp_obj_complex_t;")
871 print("#endif")
Damien Georgec51c8832016-09-03 00:19:02 +1000872 print()
873
Dave Hylands39eef272018-12-11 14:55:26 -0800874 if len(new) > 0:
Damien George69661f32020-02-27 15:36:53 +1100875 print("enum {")
Dave Hylands39eef272018-12-11 14:55:26 -0800876 for i in range(len(new)):
877 if i == 0:
Damien George69661f32020-02-27 15:36:53 +1100878 print(" MP_QSTR_%s = MP_QSTRnumber_of," % new[i][1])
Dave Hylands39eef272018-12-11 14:55:26 -0800879 else:
Damien George69661f32020-02-27 15:36:53 +1100880 print(" MP_QSTR_%s," % new[i][1])
881 print("};")
Damien George0699c6b2016-01-31 21:45:22 +0000882
Rich Barlow6e5a40c2018-07-19 12:42:26 +0100883 # As in qstr.c, set so that the first dynamically allocated pool is twice this size; must be <= the len
884 qstr_pool_alloc = min(len(new), 10)
885
Damien George0699c6b2016-01-31 21:45:22 +0000886 print()
Damien George69661f32020-02-27 15:36:53 +1100887 print("extern const qstr_pool_t mp_qstr_const_pool;")
888 print("const qstr_pool_t mp_qstr_frozen_const_pool = {")
889 print(" (qstr_pool_t*)&mp_qstr_const_pool, // previous pool")
890 print(" MP_QSTRnumber_of, // previous pool size")
891 print(" %u, // allocated entries" % qstr_pool_alloc)
892 print(" %u, // used entries" % len(new))
893 print(" {")
Damien George0699c6b2016-01-31 21:45:22 +0000894 for _, _, qstr in new:
Damien George69661f32020-02-27 15:36:53 +1100895 print(
896 " %s,"
897 % qstrutil.make_bytes(
898 config.MICROPY_QSTR_BYTES_IN_LEN, config.MICROPY_QSTR_BYTES_IN_HASH, qstr
899 )
900 )
901 print(" },")
902 print("};")
Damien George0699c6b2016-01-31 21:45:22 +0000903
904 for rc in raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100905 rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_")
Damien George0699c6b2016-01-31 21:45:22 +0000906
907 print()
Damien George69661f32020-02-27 15:36:53 +1100908 print("const char mp_frozen_mpy_names[] = {")
Damien George0699c6b2016-01-31 21:45:22 +0000909 for rc in raw_codes:
Damien George9b4c0132016-05-23 12:46:02 +0100910 module_name = rc.source_file.str
Damien George0699c6b2016-01-31 21:45:22 +0000911 print('"%s\\0"' % module_name)
912 print('"\\0"};')
913
Damien George69661f32020-02-27 15:36:53 +1100914 print("const mp_raw_code_t *const mp_frozen_mpy_content[] = {")
Damien George0699c6b2016-01-31 21:45:22 +0000915 for rc in raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100916 print(" &raw_code_%s," % rc.escaped_name)
917 print("};")
918
Damien Georgefe16e782021-01-16 02:01:26 +1100919 # If a port defines MICROPY_FROZEN_LIST_ITEM then list all modules wrapped in that macro.
920 print("#ifdef MICROPY_FROZEN_LIST_ITEM")
921 for rc in raw_codes:
922 module_name = rc.source_file.str
923 if module_name.endswith("/__init__.py"):
924 short_name = module_name[: -len("/__init__.py")]
925 else:
926 short_name = module_name[: -len(".py")]
927 print('MICROPY_FROZEN_LIST_ITEM("%s", "%s")' % (short_name, module_name))
928 print("#endif")
929
Damien George0699c6b2016-01-31 21:45:22 +0000930
Damien George27879842019-10-09 14:23:15 +1100931def merge_mpy(raw_codes, output_file):
Damien George69661f32020-02-27 15:36:53 +1100932 assert len(raw_codes) <= 31 # so var-uints all fit in 1 byte
Damien George27879842019-10-09 14:23:15 +1100933 merged_mpy = bytearray()
934
935 if len(raw_codes) == 1:
Damien George69661f32020-02-27 15:36:53 +1100936 with open(raw_codes[0].mpy_source_file, "rb") as f:
Damien George27879842019-10-09 14:23:15 +1100937 merged_mpy.extend(f.read())
938 else:
939 header = bytearray(5)
Damien George69661f32020-02-27 15:36:53 +1100940 header[0] = ord("M")
Damien George27879842019-10-09 14:23:15 +1100941 header[1] = config.MPY_VERSION
Damien George69661f32020-02-27 15:36:53 +1100942 header[2] = (
943 config.native_arch << 2
Damien George27879842019-10-09 14:23:15 +1100944 | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1
Damien George69661f32020-02-27 15:36:53 +1100945 | config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
946 )
Damien George27879842019-10-09 14:23:15 +1100947 header[3] = config.mp_small_int_bits
Damien George69661f32020-02-27 15:36:53 +1100948 header[4] = 32 # qstr_win_size
Damien George27879842019-10-09 14:23:15 +1100949 merged_mpy.extend(header)
950
951 bytecode = bytearray()
Damien George4f2fe342020-09-04 16:12:09 +1000952 bytecode_len = 6 + len(raw_codes) * 5 + 2
Damien George69661f32020-02-27 15:36:53 +1100953 bytecode.append(bytecode_len << 2) # kind and length
954 bytecode.append(0b00000000) # signature prelude
955 bytecode.append(0b00001000) # size prelude
956 bytecode.extend(b"\x00\x01") # MP_QSTR_
957 bytecode.extend(b"\x00\x01") # MP_QSTR_
Damien George27879842019-10-09 14:23:15 +1100958 for idx in range(len(raw_codes)):
Damien George69661f32020-02-27 15:36:53 +1100959 bytecode.append(0x32) # MP_BC_MAKE_FUNCTION
960 bytecode.append(idx) # index raw code
Damien George4f2fe342020-09-04 16:12:09 +1000961 bytecode.extend(b"\x34\x00\x59") # MP_BC_CALL_FUNCTION, 0 args, MP_BC_POP_TOP
Damien George69661f32020-02-27 15:36:53 +1100962 bytecode.extend(b"\x51\x63") # MP_BC_LOAD_NONE, MP_BC_RETURN_VALUE
Damien George27879842019-10-09 14:23:15 +1100963
Damien George69661f32020-02-27 15:36:53 +1100964 bytecode.append(0) # n_obj
965 bytecode.append(len(raw_codes)) # n_raw_code
Damien George27879842019-10-09 14:23:15 +1100966
967 merged_mpy.extend(bytecode)
968
969 for rc in raw_codes:
Damien George69661f32020-02-27 15:36:53 +1100970 with open(rc.mpy_source_file, "rb") as f:
971 f.read(4) # skip header
972 read_uint(f) # skip qstr_win_size
973 data = f.read() # read rest of mpy file
Damien George27879842019-10-09 14:23:15 +1100974 merged_mpy.extend(data)
975
976 if output_file is None:
977 sys.stdout.buffer.write(merged_mpy)
978 else:
Damien George69661f32020-02-27 15:36:53 +1100979 with open(output_file, "wb") as f:
Damien George27879842019-10-09 14:23:15 +1100980 f.write(merged_mpy)
981
Damien George69661f32020-02-27 15:36:53 +1100982
Damien George0699c6b2016-01-31 21:45:22 +0000983def main():
984 import argparse
Damien George69661f32020-02-27 15:36:53 +1100985
986 cmd_parser = argparse.ArgumentParser(description="A tool to work with MicroPython .mpy files.")
987 cmd_parser.add_argument("-d", "--dump", action="store_true", help="dump contents of files")
988 cmd_parser.add_argument("-f", "--freeze", action="store_true", help="freeze files")
989 cmd_parser.add_argument(
990 "--merge", action="store_true", help="merge multiple .mpy files into one"
991 )
992 cmd_parser.add_argument("-q", "--qstr-header", help="qstr header file to freeze against")
993 cmd_parser.add_argument(
994 "-mlongint-impl",
995 choices=["none", "longlong", "mpz"],
996 default="mpz",
997 help="long-int implementation used by target (default mpz)",
998 )
999 cmd_parser.add_argument(
1000 "-mmpz-dig-size",
1001 metavar="N",
1002 type=int,
1003 default=16,
1004 help="mpz digit size used by target (default 16)",
1005 )
1006 cmd_parser.add_argument("-o", "--output", default=None, help="output file")
1007 cmd_parser.add_argument("files", nargs="+", help="input .mpy files")
Damien George0699c6b2016-01-31 21:45:22 +00001008 args = cmd_parser.parse_args()
1009
1010 # set config values relevant to target machine
1011 config.MICROPY_LONGINT_IMPL = {
Damien George69661f32020-02-27 15:36:53 +11001012 "none": config.MICROPY_LONGINT_IMPL_NONE,
1013 "longlong": config.MICROPY_LONGINT_IMPL_LONGLONG,
1014 "mpz": config.MICROPY_LONGINT_IMPL_MPZ,
Damien George0699c6b2016-01-31 21:45:22 +00001015 }[args.mlongint_impl]
1016 config.MPZ_DIG_SIZE = args.mmpz_dig_size
Damien Georgefaf3d3e2019-06-04 22:13:32 +10001017 config.native_arch = MP_NATIVE_ARCH_NONE
Damien George0699c6b2016-01-31 21:45:22 +00001018
Damien Georgeb4790af2016-09-02 15:09:21 +10001019 # set config values for qstrs, and get the existing base set of qstrs
Damien George0699c6b2016-01-31 21:45:22 +00001020 if args.qstr_header:
1021 qcfgs, base_qstrs = qstrutil.parse_input_headers([args.qstr_header])
Damien George69661f32020-02-27 15:36:53 +11001022 config.MICROPY_QSTR_BYTES_IN_LEN = int(qcfgs["BYTES_IN_LEN"])
1023 config.MICROPY_QSTR_BYTES_IN_HASH = int(qcfgs["BYTES_IN_HASH"])
Damien George0699c6b2016-01-31 21:45:22 +00001024 else:
Damien Georgeb4790af2016-09-02 15:09:21 +10001025 config.MICROPY_QSTR_BYTES_IN_LEN = 1
1026 config.MICROPY_QSTR_BYTES_IN_HASH = 1
1027 base_qstrs = {}
Damien George0699c6b2016-01-31 21:45:22 +00001028
1029 raw_codes = [read_mpy(file) for file in args.files]
1030
1031 if args.dump:
1032 dump_mpy(raw_codes)
1033 elif args.freeze:
1034 try:
Damien Georgeb4790af2016-09-02 15:09:21 +10001035 freeze_mpy(base_qstrs, raw_codes)
Damien George0699c6b2016-01-31 21:45:22 +00001036 except FreezeError as er:
1037 print(er, file=sys.stderr)
1038 sys.exit(1)
Damien George27879842019-10-09 14:23:15 +11001039 elif args.merge:
1040 merged_mpy = merge_mpy(raw_codes, args.output)
Damien George0699c6b2016-01-31 21:45:22 +00001041
Damien George69661f32020-02-27 15:36:53 +11001042
1043if __name__ == "__main__":
Damien George0699c6b2016-01-31 21:45:22 +00001044 main()