LCOV - code coverage report
Current view: top level - py - persistentcode.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-724-gfb7d21153.info Lines: 172 180 95.6 %
Date: 2022-12-01 09:37:31 Functions: 9 10 90.0 %
Branches: 94 104 90.4 %

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

Generated by: LCOV version 1.15-5-g462f71d