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

Generated by: LCOV version 1.15-5-g462f71d