LCOV - code coverage report
Current view: top level - py - persistentcode.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-190-g0a9cc9014.info Lines: 204 211 96.7 %
Date: 2025-01-15 04:59:28 Functions: 11 12 91.7 %
Branches: 108 116 93.1 %

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

Generated by: LCOV version 1.15-5-g462f71d