LCOV - code coverage report
Current view: top level - py - persistentcode.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-74-g406bccc75.info Lines: 180 187 96.3 %
Date: 2024-12-03 15:10:00 Functions: 10 11 90.9 %
Branches: 93 100 93.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013-2020 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 <stdint.h>
      28                 :            : #include <stdio.h>
      29                 :            : #include <string.h>
      30                 :            : #include <assert.h>
      31                 :            : 
      32                 :            : #include "py/reader.h"
      33                 :            : #include "py/nativeglue.h"
      34                 :            : #include "py/persistentcode.h"
      35                 :            : #include "py/bc0.h"
      36                 :            : #include "py/objstr.h"
      37                 :            : #include "py/mpthread.h"
      38                 :            : 
      39                 :            : #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
      40                 :            : 
      41                 :            : #include "py/smallint.h"
      42                 :            : 
      43                 :            : // makeqstrdata.py has a fixed list of qstrs at the start that we can assume
      44                 :            : // are available with know indices on all MicroPython implementations, and
      45                 :            : // avoid needing to duplicate the string data in the .mpy file. This is the
      46                 :            : // last one in that list (anything with a qstr less than or equal to this is
      47                 :            : // assumed to be in the list).
      48                 :            : #define QSTR_LAST_STATIC MP_QSTR_zip
      49                 :            : 
      50                 :            : #if MICROPY_DYNAMIC_COMPILER
      51                 :            : #define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch
      52                 :            : #else
      53                 :            : #define MPY_FEATURE_ARCH_DYNAMIC MPY_FEATURE_ARCH
      54                 :            : #endif
      55                 :            : 
      56                 :            : typedef struct _bytecode_prelude_t {
      57                 :            :     uint n_state;
      58                 :            :     uint n_exc_stack;
      59                 :            :     uint scope_flags;
      60                 :            :     uint n_pos_args;
      61                 :            :     uint n_kwonly_args;
      62                 :            :     uint n_def_pos_args;
      63                 :            :     uint code_info_size;
      64                 :            : } bytecode_prelude_t;
      65                 :            : 
      66                 :            : #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
      67                 :            : 
      68                 :            : #if MICROPY_PERSISTENT_CODE_LOAD
      69                 :            : 
      70                 :            : #include "py/parsenum.h"
      71                 :            : 
      72                 :            : static int read_byte(mp_reader_t *reader);
      73                 :            : static size_t read_uint(mp_reader_t *reader);
      74                 :            : 
      75                 :            : #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA
      76                 :            : 
      77                 :            : // An mp_obj_list_t that tracks native text/BSS/rodata to prevent the GC from reclaiming them.
      78                 :            : MP_REGISTER_ROOT_POINTER(mp_obj_t persistent_code_root_pointers);
      79                 :            : 
      80                 :          8 : static void track_root_pointer(void *ptr) {
      81         [ +  - ]:          8 :     if (MP_STATE_PORT(persistent_code_root_pointers) == MP_OBJ_NULL) {
      82                 :          8 :         MP_STATE_PORT(persistent_code_root_pointers) = mp_obj_new_list(0, NULL);
      83                 :            :     }
      84                 :          8 :     mp_obj_list_append(MP_STATE_PORT(persistent_code_root_pointers), MP_OBJ_FROM_PTR(ptr));
      85                 :          8 : }
      86                 :            : 
      87                 :            : #endif
      88                 :            : 
      89                 :            : #if MICROPY_EMIT_MACHINE_CODE
      90                 :            : 
      91                 :            : typedef struct _reloc_info_t {
      92                 :            :     mp_reader_t *reader;
      93                 :            :     mp_module_context_t *context;
      94                 :            :     uint8_t *rodata;
      95                 :            :     uint8_t *bss;
      96                 :            : } reloc_info_t;
      97                 :            : 
      98                 :          8 : void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) {
      99                 :            :     // Relocate native code
     100                 :          8 :     reloc_info_t *ri = ri_in;
     101                 :          8 :     uint8_t op;
     102                 :          8 :     uintptr_t *addr_to_adjust = NULL;
     103         [ +  + ]:         48 :     while ((op = read_byte(ri->reader)) != 0xff) {
     104         [ +  - ]:         40 :         if (op & 1) {
     105                 :            :             // Point to new location to make adjustments
     106                 :         40 :             size_t addr = read_uint(ri->reader);
     107         [ +  + ]:         40 :             if ((addr & 1) == 0) {
     108                 :            :                 // Point to somewhere in text
     109                 :         36 :                 addr_to_adjust = &((uintptr_t *)text)[addr >> 1];
     110                 :            :             } else {
     111                 :            :                 // Point to somewhere in rodata
     112                 :          4 :                 addr_to_adjust = &((uintptr_t *)ri->rodata)[addr >> 1];
     113                 :            :             }
     114                 :            :         }
     115                 :         40 :         op >>= 1;
     116                 :         40 :         uintptr_t dest;
     117                 :         40 :         size_t n = 1;
     118         [ +  + ]:         40 :         if (op <= 5) {
     119         [ +  + ]:         20 :             if (op & 1) {
     120                 :            :                 // Read in number of adjustments to make
     121                 :          4 :                 n = read_uint(ri->reader);
     122                 :            :             }
     123                 :         20 :             op >>= 1;
     124         [ +  + ]:         20 :             if (op == 0) {
     125                 :            :                 // Destination is text
     126                 :         40 :                 dest = reloc_text;
     127         [ -  + ]:          4 :             } else if (op == 1) {
     128                 :            :                 // Destination is rodata
     129                 :          0 :                 dest = (uintptr_t)ri->rodata;
     130                 :            :             } else {
     131                 :            :                 // Destination is bss
     132                 :          4 :                 dest = (uintptr_t)ri->bss;
     133                 :            :             }
     134         [ +  + ]:         20 :         } else if (op == 6) {
     135                 :            :             // Destination is qstr_table
     136                 :          4 :             dest = (uintptr_t)ri->context->constants.qstr_table;
     137         [ -  + ]:         16 :         } else if (op == 7) {
     138                 :            :             // Destination is obj_table
     139                 :          0 :             dest = (uintptr_t)ri->context->constants.obj_table;
     140         [ +  + ]:         16 :         } else if (op == 8) {
     141                 :            :             // Destination is mp_fun_table itself
     142                 :          4 :             dest = (uintptr_t)&mp_fun_table;
     143                 :            :         } else {
     144                 :            :             // Destination is an entry in mp_fun_table
     145                 :         12 :             dest = ((uintptr_t *)&mp_fun_table)[op - 9];
     146                 :            :         }
     147         [ +  + ]:         76 :         while (n--) {
     148                 :         36 :             *addr_to_adjust++ += dest;
     149                 :            :         }
     150                 :            :     }
     151                 :          8 : }
     152                 :            : 
     153                 :            : #endif
     154                 :            : 
     155                 :      22407 : static int read_byte(mp_reader_t *reader) {
     156                 :      22407 :     return reader->readbyte(reader->data);
     157                 :            : }
     158                 :            : 
     159                 :      22035 : static void read_bytes(mp_reader_t *reader, byte *buf, size_t len) {
     160         [ +  + ]:    2025098 :     while (len-- > 0) {
     161                 :    2003063 :         *buf++ = reader->readbyte(reader->data);
     162                 :            :     }
     163                 :      22035 : }
     164                 :            : 
     165                 :      35200 : static size_t read_uint(mp_reader_t *reader) {
     166                 :      35200 :     size_t unum = 0;
     167                 :      44340 :     for (;;) {
     168                 :      44340 :         byte b = reader->readbyte(reader->data);
     169                 :      44340 :         unum = (unum << 7) | (b & 0x7f);
     170         [ +  + ]:      44340 :         if ((b & 0x80) == 0) {
     171                 :            :             break;
     172                 :            :         }
     173                 :            :     }
     174                 :      35200 :     return unum;
     175                 :            : }
     176                 :            : 
     177                 :      18311 : static qstr load_qstr(mp_reader_t *reader) {
     178                 :      18311 :     size_t len = read_uint(reader);
     179         [ +  + ]:      18311 :     if (len & 1) {
     180                 :            :         // static qstr
     181                 :       7982 :         return len >> 1;
     182                 :            :     }
     183                 :      10329 :     len >>= 1;
     184                 :      10329 :     char *str = m_new(char, len);
     185                 :      10329 :     read_bytes(reader, (byte *)str, len);
     186                 :      10329 :     read_byte(reader); // read and discard null terminator
     187                 :      10329 :     qstr qst = qstr_from_strn(str, len);
     188                 :      10329 :     m_del(char, str, len);
     189                 :      10329 :     return qst;
     190                 :            : }
     191                 :            : 
     192                 :       7522 : static mp_obj_t load_obj(mp_reader_t *reader) {
     193                 :       7522 :     byte obj_type = read_byte(reader);
     194                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     195   [ +  +  +  +  :       7522 :     if (obj_type == MP_PERSISTENT_OBJ_FUN_TABLE) {
                   +  + ]
     196                 :            :         return MP_OBJ_FROM_PTR(&mp_fun_table);
     197                 :            :     } else
     198                 :            :     #endif
     199                 :            :     if (obj_type == MP_PERSISTENT_OBJ_NONE) {
     200                 :          4 :         return mp_const_none;
     201                 :            :     } else if (obj_type == MP_PERSISTENT_OBJ_FALSE) {
     202                 :          8 :         return mp_const_false;
     203                 :            :     } else if (obj_type == MP_PERSISTENT_OBJ_TRUE) {
     204                 :         10 :         return mp_const_true;
     205                 :            :     } else if (obj_type == MP_PERSISTENT_OBJ_ELLIPSIS) {
     206                 :          6 :         return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj);
     207                 :            :     } else {
     208                 :       6779 :         size_t len = read_uint(reader);
     209         [ +  + ]:       6779 :         if (len == 0 && obj_type == MP_PERSISTENT_OBJ_BYTES) {
     210                 :         40 :             read_byte(reader); // skip null terminator
     211                 :         40 :             return mp_const_empty_bytes;
     212         [ +  + ]:       6739 :         } else if (obj_type == MP_PERSISTENT_OBJ_TUPLE) {
     213                 :        453 :             mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
     214         [ +  + ]:       1707 :             for (size_t i = 0; i < len; ++i) {
     215                 :       1254 :                 tuple->items[i] = load_obj(reader);
     216                 :            :             }
     217                 :            :             return MP_OBJ_FROM_PTR(tuple);
     218                 :            :         }
     219                 :       6286 :         vstr_t vstr;
     220                 :       6286 :         vstr_init_len(&vstr, len);
     221                 :       6286 :         read_bytes(reader, (byte *)vstr.buf, len);
     222         [ +  + ]:       6286 :         if (obj_type == MP_PERSISTENT_OBJ_STR || obj_type == MP_PERSISTENT_OBJ_BYTES) {
     223                 :       4468 :             read_byte(reader); // skip null terminator
     224         [ +  + ]:       4468 :             if (obj_type == MP_PERSISTENT_OBJ_STR) {
     225                 :       3850 :                 return mp_obj_new_str_from_utf8_vstr(&vstr);
     226                 :            :             } else {
     227                 :        618 :                 return mp_obj_new_bytes_from_vstr(&vstr);
     228                 :            :             }
     229         [ +  + ]:       1818 :         } else if (obj_type == MP_PERSISTENT_OBJ_INT) {
     230                 :       1242 :             return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
     231                 :            :         } else {
     232         [ -  + ]:        576 :             assert(obj_type == MP_PERSISTENT_OBJ_FLOAT || obj_type == MP_PERSISTENT_OBJ_COMPLEX);
     233                 :        576 :             return mp_parse_num_float(vstr.buf, vstr.len, obj_type == MP_PERSISTENT_OBJ_COMPLEX, NULL);
     234                 :            :         }
     235                 :            :     }
     236                 :            : }
     237                 :            : 
     238                 :       4025 : static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *context) {
     239                 :            :     // Load function kind and data length
     240                 :       4025 :     size_t kind_len = read_uint(reader);
     241                 :       4025 :     int kind = (kind_len & 3) + MP_CODE_BYTECODE;
     242                 :       4025 :     bool has_children = !!(kind_len & 4);
     243                 :       4025 :     size_t fun_data_len = kind_len >> 3;
     244                 :            : 
     245                 :            :     #if !MICROPY_EMIT_MACHINE_CODE
     246                 :            :     if (kind != MP_CODE_BYTECODE) {
     247                 :            :         mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file"));
     248                 :            :     }
     249                 :            :     #endif
     250                 :            : 
     251                 :       4025 :     uint8_t *fun_data = NULL;
     252                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     253                 :       4025 :     size_t prelude_offset = 0;
     254                 :       4025 :     mp_uint_t native_scope_flags = 0;
     255                 :       4025 :     mp_uint_t native_n_pos_args = 0;
     256                 :       4025 :     mp_uint_t native_type_sig = 0;
     257                 :            :     #endif
     258                 :            : 
     259         [ +  + ]:       4025 :     if (kind == MP_CODE_BYTECODE) {
     260                 :            :         // Allocate memory for the bytecode
     261                 :       1912 :         fun_data = m_new(uint8_t, fun_data_len);
     262                 :            :         // Load bytecode
     263                 :       1912 :         read_bytes(reader, fun_data, fun_data_len);
     264                 :            : 
     265                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     266                 :            :     } else {
     267                 :            :         // Allocate memory for native data and load it
     268                 :       2113 :         size_t fun_alloc;
     269                 :       2113 :         MP_PLAT_ALLOC_EXEC(fun_data_len, (void **)&fun_data, &fun_alloc);
     270                 :       2113 :         read_bytes(reader, fun_data, fun_data_len);
     271                 :            : 
     272         [ +  + ]:       2113 :         if (kind == MP_CODE_NATIVE_PY) {
     273                 :            :             // Read prelude offset within fun_data, and extract scope flags.
     274                 :       1891 :             prelude_offset = read_uint(reader);
     275                 :       1891 :             const byte *ip = fun_data + prelude_offset;
     276         [ +  + ]:       2219 :             MP_BC_PRELUDE_SIG_DECODE(ip);
     277                 :       2113 :             native_scope_flags = scope_flags;
     278                 :            :         } else {
     279                 :            :             // Load basic scope info for viper and asm.
     280                 :        222 :             native_scope_flags = read_uint(reader);
     281         [ +  + ]:        222 :             if (kind == MP_CODE_NATIVE_ASM) {
     282                 :          4 :                 native_n_pos_args = read_uint(reader);
     283                 :          4 :                 native_type_sig = read_uint(reader);
     284                 :            :             }
     285                 :            :         }
     286                 :            :     #endif
     287                 :            :     }
     288                 :            : 
     289                 :       4025 :     size_t n_children = 0;
     290                 :       4025 :     mp_raw_code_t **children = NULL;
     291                 :            : 
     292                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     293                 :            :     // Load optional BSS/rodata for viper.
     294                 :       4025 :     uint8_t *rodata = NULL;
     295                 :       4025 :     uint8_t *bss = NULL;
     296         [ +  + ]:       4025 :     if (kind == MP_CODE_NATIVE_VIPER) {
     297                 :        218 :         size_t rodata_size = 0;
     298         [ +  + ]:        218 :         if (native_scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
     299                 :          4 :             rodata_size = read_uint(reader);
     300                 :            :         }
     301                 :            : 
     302                 :        218 :         size_t bss_size = 0;
     303         [ +  + ]:        218 :         if (native_scope_flags & MP_SCOPE_FLAG_VIPERBSS) {
     304                 :          8 :             bss_size = read_uint(reader);
     305                 :            :         }
     306                 :            : 
     307         [ +  + ]:        218 :         if (rodata_size + bss_size != 0) {
     308                 :          8 :             bss_size = (uintptr_t)MP_ALIGN(bss_size, sizeof(uintptr_t));
     309                 :          8 :             uint8_t *data = m_new0(uint8_t, bss_size + rodata_size);
     310                 :          8 :             bss = data;
     311                 :          8 :             rodata = bss + bss_size;
     312         [ +  + ]:          8 :             if (native_scope_flags & MP_SCOPE_FLAG_VIPERRODATA) {
     313                 :          4 :                 read_bytes(reader, rodata, rodata_size);
     314                 :            :             }
     315                 :            : 
     316                 :            :             #if MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA
     317                 :            :             // Track the BSS/rodata memory so it's not reclaimed by the GC.
     318                 :          8 :             track_root_pointer(data);
     319                 :            :             #endif
     320                 :            :         }
     321                 :            :     }
     322                 :            :     #endif
     323                 :            : 
     324                 :            :     // Load children if any.
     325         [ +  + ]:       4025 :     if (has_children) {
     326                 :       1162 :         n_children = read_uint(reader);
     327                 :       1162 :         children = m_new(mp_raw_code_t *, n_children + (kind == MP_CODE_NATIVE_PY));
     328         [ +  + ]:       3814 :         for (size_t i = 0; i < n_children; ++i) {
     329                 :       2652 :             children[i] = load_raw_code(reader, context);
     330                 :            :         }
     331                 :            :     }
     332                 :            : 
     333                 :            :     // Create raw_code and return it
     334                 :       4025 :     mp_raw_code_t *rc = mp_emit_glue_new_raw_code();
     335         [ +  + ]:       4025 :     if (kind == MP_CODE_BYTECODE) {
     336                 :       1912 :         const byte *ip = fun_data;
     337         [ +  + ]:       2314 :         MP_BC_PRELUDE_SIG_DECODE(ip);
     338                 :            :         // Assign bytecode to raw code object
     339                 :       1912 :         mp_emit_glue_assign_bytecode(rc, fun_data,
     340                 :            :             children,
     341                 :            :             #if MICROPY_PERSISTENT_CODE_SAVE
     342                 :            :             fun_data_len,
     343                 :            :             n_children,
     344                 :            :             #endif
     345                 :            :             scope_flags);
     346                 :            : 
     347                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     348                 :            :     } else {
     349                 :       2113 :         const uint8_t *prelude_ptr;
     350                 :            :         #if MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE
     351                 :            :         if (kind == MP_CODE_NATIVE_PY) {
     352                 :            :             // Executable code cannot be accessed byte-wise on this architecture, so copy
     353                 :            :             // the prelude to a separate memory region that is byte-wise readable.
     354                 :            :             void *buf = fun_data + prelude_offset;
     355                 :            :             size_t n = fun_data_len - prelude_offset;
     356                 :            :             prelude_ptr = memcpy(m_new(uint8_t, n), buf, n);
     357                 :            :         }
     358                 :            :         #endif
     359                 :            : 
     360                 :            :         // Relocate and commit code to executable address space
     361                 :       2113 :         reloc_info_t ri = {reader, context, rodata, bss};
     362                 :            :         #if defined(MP_PLAT_COMMIT_EXEC)
     363                 :            :         void *opt_ri = (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL;
     364                 :            :         fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri);
     365                 :            :         #else
     366         [ +  + ]:       2113 :         if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) {
     367                 :            :             #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA
     368                 :            :             // Track the function data memory so it's not reclaimed by the GC.
     369                 :            :             track_root_pointer(fun_data);
     370                 :            :             #endif
     371                 :            :             // Do the relocations.
     372                 :          8 :             mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data);
     373                 :            :         }
     374                 :            :         #endif
     375                 :            : 
     376         [ +  + ]:       2113 :         if (kind == MP_CODE_NATIVE_PY) {
     377                 :            :             #if !MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE
     378                 :       1891 :             prelude_ptr = fun_data + prelude_offset;
     379                 :            :             #endif
     380         [ +  + ]:       1891 :             if (n_children == 0) {
     381                 :            :                 children = (void *)prelude_ptr;
     382                 :            :             } else {
     383                 :        570 :                 children[n_children] = (void *)prelude_ptr;
     384                 :            :             }
     385                 :            :         }
     386                 :            : 
     387                 :            :         // Assign native code to raw code object
     388                 :       2113 :         mp_emit_glue_assign_native(rc, kind,
     389                 :            :             fun_data, fun_data_len,
     390                 :            :             children,
     391                 :            :             #if MICROPY_PERSISTENT_CODE_SAVE
     392                 :            :             n_children,
     393                 :            :             prelude_offset,
     394                 :            :             #endif
     395                 :            :             native_scope_flags, native_n_pos_args, native_type_sig
     396                 :            :             );
     397                 :            :     #endif
     398                 :            :     }
     399                 :       4025 :     return rc;
     400                 :            : }
     401                 :            : 
     402                 :       1391 : void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) {
     403                 :            :     // Set exception handler to close the reader if an exception is raised.
     404                 :       1391 :     MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, reader->close, reader->data);
     405                 :       1391 :     nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback);
     406                 :            : 
     407                 :       1391 :     byte header[4];
     408                 :       1391 :     read_bytes(reader, header, sizeof(header));
     409                 :       1391 :     byte arch = MPY_FEATURE_DECODE_ARCH(header[2]);
     410         [ +  + ]:       1391 :     if (header[0] != 'M'
     411         [ +  + ]:       1385 :         || header[1] != MPY_VERSION
     412   [ +  +  +  - ]:       1377 :         || (arch != MP_NATIVE_ARCH_NONE && MPY_FEATURE_DECODE_SUB_VERSION(header[2]) != MPY_SUB_VERSION)
     413         [ -  + ]:       1377 :         || header[3] > MP_SMALL_INT_BITS) {
     414                 :         14 :         mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file"));
     415                 :            :     }
     416         [ +  + ]:       1377 :     if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) {
     417         [ +  + ]:        731 :         if (!MPY_FEATURE_ARCH_TEST(arch)) {
     418                 :          4 :             if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_NONE)) {
     419                 :            :                 // On supported ports this can be resolved by enabling feature, eg
     420                 :            :                 // mpconfigboard.h: MICROPY_EMIT_THUMB (1)
     421                 :            :                 mp_raise_ValueError(MP_ERROR_TEXT("native code in .mpy unsupported"));
     422                 :            :             } else {
     423                 :          4 :                 mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy arch"));
     424                 :            :             }
     425                 :            :         }
     426                 :            :     }
     427                 :            : 
     428                 :       1373 :     size_t n_qstr = read_uint(reader);
     429                 :       1373 :     size_t n_obj = read_uint(reader);
     430                 :       1373 :     mp_module_context_alloc_tables(cm->context, n_qstr, n_obj);
     431                 :            : 
     432                 :            :     // Load qstrs.
     433         [ +  + ]:      19684 :     for (size_t i = 0; i < n_qstr; ++i) {
     434                 :      18311 :         cm->context->constants.qstr_table[i] = load_qstr(reader);
     435                 :            :     }
     436                 :            : 
     437                 :            :     // Load constant objects.
     438         [ +  + ]:       7641 :     for (size_t i = 0; i < n_obj; ++i) {
     439                 :       6268 :         cm->context->constants.obj_table[i] = load_obj(reader);
     440                 :            :     }
     441                 :            : 
     442                 :            :     // Load top-level module.
     443                 :       1373 :     cm->rc = load_raw_code(reader, cm->context);
     444                 :            : 
     445                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
     446                 :            :     cm->has_native = MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE;
     447                 :            :     cm->n_qstr = n_qstr;
     448                 :            :     cm->n_obj = n_obj;
     449                 :            :     #endif
     450                 :            : 
     451                 :            :     // Deregister exception handler and close the reader.
     452                 :       1373 :     nlr_pop_jump_callback(true);
     453                 :       1373 : }
     454                 :            : 
     455                 :          0 : void mp_raw_code_load_mem(const byte *buf, size_t len, mp_compiled_module_t *context) {
     456                 :          0 :     mp_reader_t reader;
     457                 :          0 :     mp_reader_new_mem(&reader, buf, len, 0);
     458                 :          0 :     mp_raw_code_load(&reader, context);
     459                 :          0 : }
     460                 :            : 
     461                 :            : #if MICROPY_HAS_FILE_READER
     462                 :            : 
     463                 :       1391 : void mp_raw_code_load_file(qstr filename, mp_compiled_module_t *context) {
     464                 :       1391 :     mp_reader_t reader;
     465                 :       1391 :     mp_reader_new_file(&reader, filename);
     466                 :       1391 :     mp_raw_code_load(&reader, context);
     467                 :       1373 : }
     468                 :            : 
     469                 :            : #endif // MICROPY_HAS_FILE_READER
     470                 :            : 
     471                 :            : #endif // MICROPY_PERSISTENT_CODE_LOAD
     472                 :            : 
     473                 :            : #if MICROPY_PERSISTENT_CODE_SAVE
     474                 :            : 
     475                 :            : #include "py/objstr.h"
     476                 :            : 
     477                 :            : static void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) {
     478                 :            :     print->print_strn(print->data, (const char *)data, len);
     479                 :            : }
     480                 :            : 
     481                 :            : #define BYTES_FOR_INT ((MP_BYTES_PER_OBJ_WORD * 8 + 6) / 7)
     482                 :            : static void mp_print_uint(mp_print_t *print, size_t n) {
     483                 :            :     byte buf[BYTES_FOR_INT];
     484                 :            :     byte *p = buf + sizeof(buf);
     485                 :            :     *--p = n & 0x7f;
     486                 :            :     n >>= 7;
     487                 :            :     for (; n != 0; n >>= 7) {
     488                 :            :         *--p = 0x80 | (n & 0x7f);
     489                 :            :     }
     490                 :            :     print->print_strn(print->data, (char *)p, buf + sizeof(buf) - p);
     491                 :            : }
     492                 :            : 
     493                 :            : static void save_qstr(mp_print_t *print, qstr qst) {
     494                 :            :     if (qst <= QSTR_LAST_STATIC) {
     495                 :            :         // encode static qstr
     496                 :            :         mp_print_uint(print, qst << 1 | 1);
     497                 :            :         return;
     498                 :            :     }
     499                 :            :     size_t len;
     500                 :            :     const byte *str = qstr_data(qst, &len);
     501                 :            :     mp_print_uint(print, len << 1);
     502                 :            :     mp_print_bytes(print, str, len + 1); // +1 to store null terminator
     503                 :            : }
     504                 :            : 
     505                 :            : static void save_obj(mp_print_t *print, mp_obj_t o) {
     506                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     507                 :            :     if (o == MP_OBJ_FROM_PTR(&mp_fun_table)) {
     508                 :            :         byte obj_type = MP_PERSISTENT_OBJ_FUN_TABLE;
     509                 :            :         mp_print_bytes(print, &obj_type, 1);
     510                 :            :     } else
     511                 :            :     #endif
     512                 :            :     if (mp_obj_is_str_or_bytes(o)) {
     513                 :            :         byte obj_type;
     514                 :            :         if (mp_obj_is_str(o)) {
     515                 :            :             obj_type = MP_PERSISTENT_OBJ_STR;
     516                 :            :         } else {
     517                 :            :             obj_type = MP_PERSISTENT_OBJ_BYTES;
     518                 :            :         }
     519                 :            :         size_t len;
     520                 :            :         const char *str = mp_obj_str_get_data(o, &len);
     521                 :            :         mp_print_bytes(print, &obj_type, 1);
     522                 :            :         mp_print_uint(print, len);
     523                 :            :         mp_print_bytes(print, (const byte *)str, len + 1); // +1 to store null terminator
     524                 :            :     } else if (o == mp_const_none) {
     525                 :            :         byte obj_type = MP_PERSISTENT_OBJ_NONE;
     526                 :            :         mp_print_bytes(print, &obj_type, 1);
     527                 :            :     } else if (o == mp_const_false) {
     528                 :            :         byte obj_type = MP_PERSISTENT_OBJ_FALSE;
     529                 :            :         mp_print_bytes(print, &obj_type, 1);
     530                 :            :     } else if (o == mp_const_true) {
     531                 :            :         byte obj_type = MP_PERSISTENT_OBJ_TRUE;
     532                 :            :         mp_print_bytes(print, &obj_type, 1);
     533                 :            :     } else if (MP_OBJ_TO_PTR(o) == &mp_const_ellipsis_obj) {
     534                 :            :         byte obj_type = MP_PERSISTENT_OBJ_ELLIPSIS;
     535                 :            :         mp_print_bytes(print, &obj_type, 1);
     536                 :            :     } else if (mp_obj_is_type(o, &mp_type_tuple)) {
     537                 :            :         size_t len;
     538                 :            :         mp_obj_t *items;
     539                 :            :         mp_obj_tuple_get(o, &len, &items);
     540                 :            :         byte obj_type = MP_PERSISTENT_OBJ_TUPLE;
     541                 :            :         mp_print_bytes(print, &obj_type, 1);
     542                 :            :         mp_print_uint(print, len);
     543                 :            :         for (size_t i = 0; i < len; ++i) {
     544                 :            :             save_obj(print, items[i]);
     545                 :            :         }
     546                 :            :     } else {
     547                 :            :         // we save numbers using a simplistic text representation
     548                 :            :         // TODO could be improved
     549                 :            :         byte obj_type;
     550                 :            :         if (mp_obj_is_int(o)) {
     551                 :            :             obj_type = MP_PERSISTENT_OBJ_INT;
     552                 :            :         #if MICROPY_PY_BUILTINS_COMPLEX
     553                 :            :         } else if (mp_obj_is_type(o, &mp_type_complex)) {
     554                 :            :             obj_type = MP_PERSISTENT_OBJ_COMPLEX;
     555                 :            :         #endif
     556                 :            :         } else {
     557                 :            :             assert(mp_obj_is_float(o));
     558                 :            :             obj_type = MP_PERSISTENT_OBJ_FLOAT;
     559                 :            :         }
     560                 :            :         vstr_t vstr;
     561                 :            :         mp_print_t pr;
     562                 :            :         vstr_init_print(&vstr, 10, &pr);
     563                 :            :         mp_obj_print_helper(&pr, o, PRINT_REPR);
     564                 :            :         mp_print_bytes(print, &obj_type, 1);
     565                 :            :         mp_print_uint(print, vstr.len);
     566                 :            :         mp_print_bytes(print, (const byte *)vstr.buf, vstr.len);
     567                 :            :         vstr_clear(&vstr);
     568                 :            :     }
     569                 :            : }
     570                 :            : 
     571                 :            : static void save_raw_code(mp_print_t *print, const mp_raw_code_t *rc) {
     572                 :            :     // Save function kind and data length
     573                 :            :     mp_print_uint(print, (rc->fun_data_len << 3) | ((rc->n_children != 0) << 2) | (rc->kind - MP_CODE_BYTECODE));
     574                 :            : 
     575                 :            :     // Save function code.
     576                 :            :     mp_print_bytes(print, rc->fun_data, rc->fun_data_len);
     577                 :            : 
     578                 :            :     #if MICROPY_EMIT_MACHINE_CODE
     579                 :            :     if (rc->kind == MP_CODE_NATIVE_PY) {
     580                 :            :         // Save prelude size
     581                 :            :         mp_print_uint(print, rc->prelude_offset);
     582                 :            :     } else if (rc->kind == MP_CODE_NATIVE_VIPER || rc->kind == MP_CODE_NATIVE_ASM) {
     583                 :            :         // Save basic scope info for viper and asm
     584                 :            :         // Viper/asm functions don't support generator, variable args, or default keyword args
     585                 :            :         // so (scope_flags & MP_SCOPE_FLAG_ALL_SIG) for these functions is always 0.
     586                 :            :         mp_print_uint(print, 0);
     587                 :            :         #if MICROPY_EMIT_INLINE_ASM
     588                 :            :         if (rc->kind == MP_CODE_NATIVE_ASM) {
     589                 :            :             mp_print_uint(print, rc->asm_n_pos_args);
     590                 :            :             mp_print_uint(print, rc->asm_type_sig);
     591                 :            :         }
     592                 :            :         #endif
     593                 :            :     }
     594                 :            :     #endif
     595                 :            : 
     596                 :            :     if (rc->n_children) {
     597                 :            :         mp_print_uint(print, rc->n_children);
     598                 :            :         for (size_t i = 0; i < rc->n_children; ++i) {
     599                 :            :             save_raw_code(print, rc->children[i]);
     600                 :            :         }
     601                 :            :     }
     602                 :            : }
     603                 :            : 
     604                 :            : void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) {
     605                 :            :     // header contains:
     606                 :            :     //  byte  'M'
     607                 :            :     //  byte  version
     608                 :            :     //  byte  native arch (and sub-version if native)
     609                 :            :     //  byte  number of bits in a small int
     610                 :            :     byte header[4] = {
     611                 :            :         'M',
     612                 :            :         MPY_VERSION,
     613                 :            :         cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0,
     614                 :            :         #if MICROPY_DYNAMIC_COMPILER
     615                 :            :         mp_dynamic_compiler.small_int_bits,
     616                 :            :         #else
     617                 :            :         MP_SMALL_INT_BITS,
     618                 :            :         #endif
     619                 :            :     };
     620                 :            :     mp_print_bytes(print, header, sizeof(header));
     621                 :            : 
     622                 :            :     // Number of entries in constant table.
     623                 :            :     mp_print_uint(print, cm->n_qstr);
     624                 :            :     mp_print_uint(print, cm->n_obj);
     625                 :            : 
     626                 :            :     // Save qstrs.
     627                 :            :     for (size_t i = 0; i < cm->n_qstr; ++i) {
     628                 :            :         save_qstr(print, cm->context->constants.qstr_table[i]);
     629                 :            :     }
     630                 :            : 
     631                 :            :     // Save constant objects.
     632                 :            :     for (size_t i = 0; i < cm->n_obj; ++i) {
     633                 :            :         save_obj(print, (mp_obj_t)cm->context->constants.obj_table[i]);
     634                 :            :     }
     635                 :            : 
     636                 :            :     // Save outer raw code, which will save all its child raw codes.
     637                 :            :     save_raw_code(print, cm->rc);
     638                 :            : }
     639                 :            : 
     640                 :            : #if MICROPY_PERSISTENT_CODE_SAVE_FILE
     641                 :            : 
     642                 :            : #include <unistd.h>
     643                 :            : #include <sys/stat.h>
     644                 :            : #include <fcntl.h>
     645                 :            : 
     646                 :            : static void fd_print_strn(void *env, const char *str, size_t len) {
     647                 :            :     int fd = (intptr_t)env;
     648                 :            :     MP_THREAD_GIL_EXIT();
     649                 :            :     ssize_t ret = write(fd, str, len);
     650                 :            :     MP_THREAD_GIL_ENTER();
     651                 :            :     (void)ret;
     652                 :            : }
     653                 :            : 
     654                 :            : void mp_raw_code_save_file(mp_compiled_module_t *cm, qstr filename) {
     655                 :            :     MP_THREAD_GIL_EXIT();
     656                 :            :     int fd = open(qstr_str(filename), O_WRONLY | O_CREAT | O_TRUNC, 0644);
     657                 :            :     MP_THREAD_GIL_ENTER();
     658                 :            :     if (fd < 0) {
     659                 :            :         mp_raise_OSError_with_filename(errno, qstr_str(filename));
     660                 :            :     }
     661                 :            :     mp_print_t fd_print = {(void *)(intptr_t)fd, fd_print_strn};
     662                 :            :     mp_raw_code_save(cm, &fd_print);
     663                 :            :     MP_THREAD_GIL_EXIT();
     664                 :            :     close(fd);
     665                 :            :     MP_THREAD_GIL_ENTER();
     666                 :            : }
     667                 :            : 
     668                 :            : #endif // MICROPY_PERSISTENT_CODE_SAVE_FILE
     669                 :            : 
     670                 :            : #endif // MICROPY_PERSISTENT_CODE_SAVE

Generated by: LCOV version 1.15-5-g462f71d