def freeze(self, parent_name): self.escaped_name = parent_name + self.simple_name.qstr_esc # make sure the escaped name is unique i = 2 while self.escaped_name in RawCode.escaped_names: self.escaped_name = parent_name + self.simple_name.qstr_esc + str(i) i += 1 RawCode.escaped_names.add(self.escaped_name) # emit children first for rc in self.raw_codes: rc.freeze(self.escaped_name + '_') # generate bytecode data print() print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) print('STATIC ', end='') if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: print('const ', end='') print('byte bytecode_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode))) print(' ', end='') for i in range(self.ip2): print(' 0x%02x,' % self.bytecode[i], end='') print() print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') print(' ', end='') for i in range(self.ip2 + 4, self.ip): print(' 0x%02x,' % self.bytecode[i], end='') print() ip = self.ip while ip < len(self.bytecode): f, sz = mp_opcode_format(self.bytecode, ip) if f == 1: qst = self._unpack_qstr(ip + 1).qstr_id print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,') else: print(' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz))) ip += sz print('};') # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) if is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): obj = bytes_cons(obj, 'utf8') obj_type = 'mp_type_str' else: obj_type = 'mp_type_bytes' print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' % (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), len(obj), ''.join(('\\x%02x' % b) for b in obj))) elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int raise FreezeError(self, 'target does not support long int') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG: # TODO raise FreezeError(self, 'freezing int to long-long is not implemented') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: neg = 0 if obj < 0: obj = -obj neg = 1 bits_per_dig = config.MPZ_DIG_SIZE digs = [] z = obj while z: digs.append(z & ((1 << bits_per_dig) - 1)) z >>= bits_per_dig ndigs = len(digs) digs = ','.join(('%#x' % d) for d in digs) print('STATIC const mp_obj_int_t %s = {{&mp_type_int}, ' '{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t[]){%s}}};' % (obj_name, neg, ndigs, ndigs, bits_per_dig, digs)) elif type(obj) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) print('#endif') elif type(obj) is complex: print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' % (obj_name, obj.real, obj.imag)) else: # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) # generate constant table print('STATIC const mp_uint_t const_table_data_%s[%u] = {' % (self.escaped_name, len(self.qstrs) + len(self.objs) + len(self.raw_codes))) for qst in self.qstrs: print(' (mp_uint_t)MP_OBJ_NEW_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): if type(self.objs[i]) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') n = struct.unpack('<I', struct.pack('<f', self.objs[i]))[0] n = ((n & ~0x3) | 2) + 0x80800000 print(' (mp_uint_t)0x%08x,' % (n,)) print('#else') print('#error "MICROPY_OBJ_REPR_D not supported with floats in frozen mpy files"') print('#endif') else: print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) for rc in self.raw_codes: print(' (mp_uint_t)&raw_code_%s,' % rc.escaped_name) print('};') # generate module if self.simple_name.str != '<module>': print('STATIC ', end='') print('const mp_raw_code_t raw_code_%s = {' % self.escaped_name) print(' .kind = MP_CODE_BYTECODE,') print(' .scope_flags = 0x%02x,' % self.prelude[2]) print(' .n_pos_args = %u,' % self.prelude[3]) print(' .data.u_byte = {') print(' .bytecode = bytecode_data_%s,' % self.escaped_name) print(' .const_table = const_table_data_%s,' % self.escaped_name) print(' #if MICROPY_PERSISTENT_CODE_SAVE') print(' .bc_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) print(' #endif') print(' },') print('};')
def freeze_constants(self): # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) if obj is MPFunTable: pass elif obj is Ellipsis: print('#define %s mp_const_ellipsis_obj' % obj_name) elif is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): obj = bytes_cons(obj, 'utf8') obj_type = 'mp_type_str' else: obj_type = 'mp_type_bytes' print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' % (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), len(obj), ''.join(('\\x%02x' % b) for b in obj))) elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int raise FreezeError(self, 'target does not support long int') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG: # TODO raise FreezeError(self, 'freezing int to long-long is not implemented') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: neg = 0 if obj < 0: obj = -obj neg = 1 bits_per_dig = config.MPZ_DIG_SIZE digs = [] z = obj while z: digs.append(z & ((1 << bits_per_dig) - 1)) z >>= bits_per_dig ndigs = len(digs) digs = ','.join(('%#x' % d) for d in digs) print('STATIC const mp_obj_int_t %s = {{&mp_type_int}, ' '{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t*)(const uint%u_t[]){%s}}};' % (obj_name, neg, ndigs, ndigs, bits_per_dig, bits_per_dig, digs)) elif type(obj) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) print('#endif') elif type(obj) is complex: print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' % (obj_name, obj.real, obj.imag)) else: raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) # generate constant table, if it has any entries const_table_len = len(self.qstrs) + len(self.objs) + len(self.raw_codes) if const_table_len: print('STATIC const mp_rom_obj_t const_table_data_%s[%u] = {' % (self.escaped_name, const_table_len)) for qst in self.qstrs: print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): if self.objs[i] is MPFunTable: print(' mp_fun_table,') elif type(self.objs[i]) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') n = struct.unpack('<I', struct.pack('<f', self.objs[i]))[0] n = ((n & ~0x3) | 2) + 0x80800000 print(' (mp_rom_obj_t)(0x%08x),' % (n,)) print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D') n = struct.unpack('<Q', struct.pack('<d', self.objs[i]))[0] n += 0x8004000000000000 print(' (mp_rom_obj_t)(0x%016x),' % (n,)) print('#endif') else: print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) for rc in self.raw_codes: print(' MP_ROM_PTR(&raw_code_%s),' % rc.escaped_name) print('};')
def freeze_mpy(base_qstrs, raw_codes): # add to qstrs new = {} for q in global_qstrs: # don't add duplicates if q is None or q.qstr_esc in base_qstrs or q.qstr_esc in new: continue new[q.qstr_esc] = (len(new), q.qstr_esc, q.str) new = sorted(new.values(), key=lambda x: x[0]) print('#include "py/bc0.h"') print('#include "py/mpconfig.h"') print('#include "py/objint.h"') print('#include "py/objstr.h"') print('#include "py/emitglue.h"') print('#include "py/nativeglue.h"') print() print( "#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u" % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ) print('#error "incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE"') print("#endif") print() print("#if MICROPY_LONGINT_IMPL != %u" % config.MICROPY_LONGINT_IMPL) print('#error "incompatible MICROPY_LONGINT_IMPL"') print("#endif") print() if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: print("#if MPZ_DIG_SIZE != %u" % config.MPZ_DIG_SIZE) print('#error "incompatible MPZ_DIG_SIZE"') print("#endif") print() print("#if MICROPY_PY_BUILTINS_FLOAT") print("typedef struct _mp_obj_float_t {") print(" mp_obj_base_t base;") print(" mp_float_t value;") print("} mp_obj_float_t;") print("#endif") print() print("#if MICROPY_PY_BUILTINS_COMPLEX") print("typedef struct _mp_obj_complex_t {") print(" mp_obj_base_t base;") print(" mp_float_t real;") print(" mp_float_t imag;") print("} mp_obj_complex_t;") print("#endif") print() if new: print("enum {") for i in range(len(new)): if i == 0: print(" MP_QSTR_%s = MP_QSTRnumber_of," % new[i][1]) else: print(" MP_QSTR_%s," % new[i][1]) print("};") print() print("const qstr_attr_t mp_qstr_frozen_const_attr[] = {") qstr_size = {"metadata": 0, "data": 0} for _, _, qstr in new: qbytes = qstrutil.bytes_cons(qstr, "utf8") print( " {%d, %d}," % (qstrutil.compute_hash(qbytes, config.MICROPY_QSTR_BYTES_IN_HASH), len(qbytes)) ) qstr_size["metadata"] += ( config.MICROPY_QSTR_BYTES_IN_LEN + config.MICROPY_QSTR_BYTES_IN_HASH ) qstr_size["data"] += len(qbytes) print("};") # As in qstr.c, set so that the first dynamically allocated pool is twice this size; must be <= the len qstr_pool_alloc = min(len(new), 10) print() print("extern const qstr_pool_t mp_qstr_const_pool;") print("const qstr_pool_t mp_qstr_frozen_const_pool = {") print(" &mp_qstr_const_pool, // previous pool") print(" MP_QSTRnumber_of, // previous pool size") print(" %u, // allocated entries" % qstr_pool_alloc) print(" %u, // used entries" % len(new)) print(" (qstr_attr_t *)mp_qstr_frozen_const_attr,") print(" {") for _, _, qstr in new: print(' "%s",' % qstrutil.escape_bytes(qstr)) print(" },") print("};") for rc in raw_codes: rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_") print() print("const char mp_frozen_mpy_names[] = {") for rc in raw_codes: module_name = rc.source_file.str print('"%s\\0"' % module_name) print('"\\0"};') print("const mp_raw_code_t *const mp_frozen_mpy_content[] = {") for rc in raw_codes: print(" &raw_code_%s," % rc.escaped_name) print("};") # If a port defines MICROPY_FROZEN_LIST_ITEM then list all modules wrapped in that macro. print("#ifdef MICROPY_FROZEN_LIST_ITEM") for rc in raw_codes: module_name = rc.source_file.str if module_name.endswith("/__init__.py"): short_name = module_name[: -len("/__init__.py")] else: short_name = module_name[: -len(".py")] print('MICROPY_FROZEN_LIST_ITEM("%s", "%s")' % (short_name, module_name)) print("#endif")
def freeze(self, parent_name): self.escaped_name = parent_name + self.simple_name.qstr_esc # make sure the escaped name is unique i = 2 while self.escaped_name in RawCode.escaped_names: self.escaped_name = parent_name + self.simple_name.qstr_esc + str( i) i += 1 RawCode.escaped_names.add(self.escaped_name) # emit children first for rc in self.raw_codes: rc.freeze(self.escaped_name + '_') # generate bytecode data print() print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) print('STATIC ', end='') if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: print('const ', end='') print('byte bytecode_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode))) print(' ', end='') for i in range(self.ip2): print(' 0x%02x,' % self.bytecode[i], end='') print() print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') print(' ', end='') for i in range(self.ip2 + 4, self.ip): print(' 0x%02x,' % self.bytecode[i], end='') print() ip = self.ip while ip < len(self.bytecode): f, sz = mp_opcode_format(self.bytecode, ip) if f == 1: qst = self._unpack_qstr(ip + 1).qstr_id print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,') else: print( ' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz))) ip += sz print('};') # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) if is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): obj = bytes_cons(obj, 'utf8') obj_type = 'mp_type_str' else: obj_type = 'mp_type_bytes' print( 'STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' % (obj_name, obj_type, qstrutil.compute_hash( obj, config.MICROPY_QSTR_BYTES_IN_HASH), len(obj), ''.join(('\\x%02x' % b) for b in obj))) elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int raise FreezeError(self, 'target does not support long int') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG: # TODO raise FreezeError( self, 'freezing int to long-long is not implemented') elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: neg = 0 if obj < 0: obj = -obj neg = 1 bits_per_dig = config.MPZ_DIG_SIZE digs = [] z = obj while z: digs.append(z & ((1 << bits_per_dig) - 1)) z >>= bits_per_dig ndigs = len(digs) digs = ','.join(('%#x' % d) for d in digs) print( 'STATIC const mp_obj_int_t %s = {{&mp_type_int}, ' '{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t[]){%s}}};' % (obj_name, neg, ndigs, ndigs, bits_per_dig, digs)) elif type(obj) is float: print( '#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B' ) print( 'STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) print('#endif') elif type(obj) is complex: print( 'STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' % (obj_name, obj.real, obj.imag)) else: # TODO raise FreezeError( self, 'freezing of object %r is not implemented' % (obj, )) # generate constant table print('STATIC const mp_uint_t const_table_data_%s[%u] = {' % (self.escaped_name, len(self.qstrs) + len(self.objs) + len(self.raw_codes))) for qst in self.qstrs: print(' (mp_uint_t)MP_OBJ_NEW_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): if type(self.objs[i]) is float: print( '#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B' ) print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') n = struct.unpack('<I', struct.pack('<f', self.objs[i]))[0] n = ((n & ~0x3) | 2) + 0x80800000 print(' (mp_uint_t)0x%08x,' % (n, )) print('#else') print( '#error "MICROPY_OBJ_REPR_D not supported with floats in frozen mpy files"' ) print('#endif') else: print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) for rc in self.raw_codes: print(' (mp_uint_t)&raw_code_%s,' % rc.escaped_name) print('};') # generate module if self.simple_name.str != '<module>': print('STATIC ', end='') print('const mp_raw_code_t raw_code_%s = {' % self.escaped_name) print(' .kind = MP_CODE_BYTECODE,') print(' .scope_flags = 0x%02x,' % self.prelude[2]) print(' .n_pos_args = %u,' % self.prelude[3]) print(' .data.u_byte = {') print(' .bytecode = bytecode_data_%s,' % self.escaped_name) print(' .const_table = const_table_data_%s,' % self.escaped_name) print(' #if MICROPY_PERSISTENT_CODE_SAVE') print(' .bc_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) print(' #endif') print(' },') print('};')