LCOV - code coverage report
Current view: top level - py - emitglue.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-324-g53d005025.info Lines: 52 52 100.0 %
Date: 2024-04-15 06:44:37 Functions: 5 5 100.0 %
Branches: 36 51 70.6 %

           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, 2014 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                 :            : // This code glues the code emitters to the runtime.
      28                 :            : 
      29                 :            : #include <stdint.h>
      30                 :            : #include <stdio.h>
      31                 :            : #include <string.h>
      32                 :            : #include <assert.h>
      33                 :            : 
      34                 :            : #include "py/emitglue.h"
      35                 :            : #include "py/runtime0.h"
      36                 :            : #include "py/bc.h"
      37                 :            : #include "py/objfun.h"
      38                 :            : #include "py/profile.h"
      39                 :            : 
      40                 :            : #if MICROPY_DEBUG_VERBOSE // print debugging info
      41                 :            : #define DEBUG_PRINT (1)
      42                 :            : #define WRITE_CODE (1)
      43                 :            : #define DEBUG_printf DEBUG_printf
      44                 :            : #define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)
      45                 :            : #else // don't print debugging info
      46                 :            : #define DEBUG_printf(...) (void)0
      47                 :            : #define DEBUG_OP_printf(...) (void)0
      48                 :            : #endif
      49                 :            : 
      50                 :            : #if MICROPY_DEBUG_PRINTERS
      51                 :            : mp_uint_t mp_verbose_flag = 0;
      52                 :            : #endif
      53                 :            : 
      54                 :      13515 : mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
      55                 :      13515 :     mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
      56                 :      13515 :     rc->kind = MP_CODE_RESERVED;
      57                 :            :     #if MICROPY_PY_SYS_SETTRACE
      58                 :            :     rc->line_of_definition = 0;
      59                 :            :     #endif
      60                 :      13515 :     return rc;
      61                 :            : }
      62                 :            : 
      63                 :       6976 : void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
      64                 :            :     mp_raw_code_t **children,
      65                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
      66                 :            :     size_t len,
      67                 :            :     uint16_t n_children,
      68                 :            :     #endif
      69                 :            :     uint16_t scope_flags) {
      70                 :            : 
      71                 :       6976 :     rc->kind = MP_CODE_BYTECODE;
      72                 :       6976 :     rc->is_generator = (scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0;
      73                 :       6976 :     rc->fun_data = code;
      74                 :       6976 :     rc->children = children;
      75                 :            : 
      76                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
      77                 :            :     rc->fun_data_len = len;
      78                 :            :     rc->n_children = n_children;
      79                 :            :     #endif
      80                 :            : 
      81                 :            :     #if MICROPY_PY_SYS_SETTRACE
      82                 :            :     mp_bytecode_prelude_t *prelude = &rc->prelude;
      83                 :            :     mp_prof_extract_prelude(code, prelude);
      84                 :            :     #endif
      85                 :            : 
      86                 :            :     #if DEBUG_PRINT
      87                 :            :     #if !MICROPY_PERSISTENT_CODE_SAVE
      88                 :            :     const size_t len = 0;
      89                 :            :     #endif
      90                 :            :     DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " flags=%x\n", code, len, (uint)scope_flags);
      91                 :            :     #endif
      92                 :       6976 : }
      93                 :            : 
      94                 :            : #if MICROPY_EMIT_MACHINE_CODE
      95                 :       6109 : void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, const void *fun_data, mp_uint_t fun_len,
      96                 :            :     mp_raw_code_t **children,
      97                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
      98                 :            :     uint16_t n_children,
      99                 :            :     uint16_t prelude_offset,
     100                 :            :     #endif
     101                 :            :     uint16_t scope_flags, uint32_t asm_n_pos_args, uint32_t asm_type_sig
     102                 :            :     ) {
     103                 :            : 
     104         [ -  + ]:       6109 :     assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
     105                 :            : 
     106                 :            :     // Some architectures require flushing/invalidation of the I/D caches,
     107                 :            :     // so that the generated native code which was created in data RAM will
     108                 :            :     // be available for execution from instruction RAM.
     109                 :            :     #if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
     110                 :            :     #if __ICACHE_PRESENT == 1
     111                 :            :     // Flush D-cache, so the code emitted is stored in RAM.
     112                 :            :     MP_HAL_CLEAN_DCACHE(fun_data, fun_len);
     113                 :            :     // Invalidate I-cache, so the newly-created code is reloaded from RAM.
     114                 :            :     SCB_InvalidateICache();
     115                 :            :     #endif
     116                 :            :     #elif MICROPY_EMIT_ARM
     117                 :            :     #if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
     118                 :            :     __builtin___clear_cache((void *)fun_data, (uint8_t *)fun_data + fun_len);
     119                 :            :     #elif defined(__arm__)
     120                 :            :     // Flush I-cache and D-cache.
     121                 :            :     asm volatile (
     122                 :            :         "0:"
     123                 :            :         "mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
     124                 :            :         "bne 0b\n"
     125                 :            :         "mov r0, #0\n"
     126                 :            :         "mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
     127                 :            :         : : : "r0", "cc");
     128                 :            :     #endif
     129                 :            :     #endif
     130                 :            : 
     131                 :       6109 :     rc->kind = kind;
     132                 :       6109 :     rc->is_generator = (scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0;
     133                 :       6109 :     rc->fun_data = fun_data;
     134                 :            : 
     135                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
     136                 :            :     rc->fun_data_len = fun_len;
     137                 :            :     #endif
     138                 :       6109 :     rc->children = children;
     139                 :            : 
     140                 :            :     #if MICROPY_PERSISTENT_CODE_SAVE
     141                 :            :     rc->n_children = n_children;
     142                 :            :     rc->prelude_offset = prelude_offset;
     143                 :            :     #endif
     144                 :            : 
     145                 :            :     #if MICROPY_EMIT_INLINE_ASM
     146                 :            :     // These two entries are only needed for MP_CODE_NATIVE_ASM.
     147                 :            :     rc->asm_n_pos_args = asm_n_pos_args;
     148                 :            :     rc->asm_type_sig = asm_type_sig;
     149                 :            :     #endif
     150                 :            : 
     151                 :            :     #if DEBUG_PRINT
     152                 :            :     DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, (uint)scope_flags);
     153                 :            :     for (mp_uint_t i = 0; i < fun_len; i++) {
     154                 :            :         if (i > 0 && i % 16 == 0) {
     155                 :            :             DEBUG_printf("\n");
     156                 :            :         }
     157                 :            :         DEBUG_printf(" %02x", ((const byte *)fun_data)[i]);
     158                 :            :     }
     159                 :            :     DEBUG_printf("\n");
     160                 :            : 
     161                 :            :     #ifdef WRITE_CODE
     162                 :            :     FILE *fp_write_code = fopen("out-code", "wb");
     163                 :            :     fwrite(fun_data, fun_len, 1, fp_write_code);
     164                 :            :     fclose(fp_write_code);
     165                 :            :     #endif
     166                 :            :     #else
     167                 :       6109 :     (void)fun_len;
     168                 :            :     #endif
     169                 :       6109 : }
     170                 :            : #endif
     171                 :            : 
     172                 :      18121 : mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, const mp_obj_t *def_args) {
     173                 :      18121 :     DEBUG_OP_printf("make_function_from_proto_fun %p\n", proto_fun);
     174         [ -  + ]:      18121 :     assert(proto_fun != NULL);
     175                 :            : 
     176                 :            :     // def_args must be MP_OBJ_NULL or a tuple
     177   [ +  +  +  +  :      18121 :     assert(def_args == NULL || def_args[0] == MP_OBJ_NULL || mp_obj_is_type(def_args[0], &mp_type_tuple));
          -  +  -  +  -  
          +  -  +  +  -  
                   -  + ]
     178                 :            : 
     179                 :            :     // def_kw_args must be MP_OBJ_NULL or a dict
     180   [ +  +  -  +  :        374 :     assert(def_args == NULL || def_args[1] == MP_OBJ_NULL || mp_obj_is_type(def_args[1], &mp_type_dict));
          -  +  -  +  -  
             +  +  -  -  
                      + ]
     181                 :            : 
     182                 :            :     #if MICROPY_MODULE_FROZEN_MPY
     183         [ +  + ]:      18121 :     if (mp_proto_fun_is_bytecode(proto_fun)) {
     184                 :        116 :         const uint8_t *bc = proto_fun;
     185                 :        116 :         mp_obj_t fun = mp_obj_new_fun_bc(def_args, bc, context, NULL);
     186         [ +  + ]:        258 :         MP_BC_PRELUDE_SIG_DECODE(bc);
     187         [ +  + ]:        116 :         if (scope_flags & MP_SCOPE_FLAG_GENERATOR) {
     188                 :          2 :             ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
     189                 :            :         }
     190                 :        116 :         return fun;
     191                 :            :     }
     192                 :            :     #endif
     193                 :            : 
     194                 :            :     // the proto-function is a mp_raw_code_t
     195                 :      18005 :     const mp_raw_code_t *rc = proto_fun;
     196                 :            : 
     197                 :            :     // make the function, depending on the raw code kind
     198                 :      18005 :     mp_obj_t fun;
     199      [ +  +  + ]:      18005 :     switch (rc->kind) {
     200                 :            :         #if MICROPY_EMIT_NATIVE
     201                 :       8132 :         case MP_CODE_NATIVE_PY:
     202                 :       8132 :             fun = mp_obj_new_fun_native(def_args, rc->fun_data, context, rc->children);
     203                 :            :             // Check for a generator function, and if so change the type of the object
     204         [ +  + ]:       8132 :             if (rc->is_generator) {
     205                 :        478 :                 ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
     206                 :            :             }
     207                 :            :             break;
     208                 :        420 :         case MP_CODE_NATIVE_VIPER:
     209                 :        420 :             fun = mp_obj_new_fun_viper(rc->fun_data, context, rc->children);
     210                 :        420 :             break;
     211                 :            :         #endif
     212                 :            :         #if MICROPY_EMIT_INLINE_ASM
     213                 :            :         case MP_CODE_NATIVE_ASM:
     214                 :            :             fun = mp_obj_new_fun_asm(rc->asm_n_pos_args, rc->fun_data, rc->asm_type_sig);
     215                 :            :             break;
     216                 :            :         #endif
     217                 :       9453 :         default:
     218                 :            :             // rc->kind should always be set and BYTECODE is the only remaining case
     219         [ -  + ]:       9453 :             assert(rc->kind == MP_CODE_BYTECODE);
     220                 :       9453 :             fun = mp_obj_new_fun_bc(def_args, rc->fun_data, context, rc->children);
     221                 :            :             // check for generator functions and if so change the type of the object
     222         [ +  + ]:       9453 :             if (rc->is_generator) {
     223                 :        575 :                 ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
     224                 :            :             }
     225                 :            : 
     226                 :            :             #if MICROPY_PY_SYS_SETTRACE
     227                 :            :             mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun);
     228                 :            :             self_fun->rc = rc;
     229                 :            :             #endif
     230                 :            : 
     231                 :            :             break;
     232                 :            :     }
     233                 :            : 
     234                 :            :     return fun;
     235                 :            : }
     236                 :            : 
     237                 :       2439 : mp_obj_t mp_make_closure_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args) {
     238                 :       2439 :     DEBUG_OP_printf("make_closure_from_proto_fun %p " UINT_FMT " %p\n", proto_fun, n_closed_over, args);
     239                 :            :     // make function object
     240                 :       2439 :     mp_obj_t ffun;
     241         [ +  + ]:       2439 :     if (n_closed_over & 0x100) {
     242                 :            :         // default positional and keyword args given
     243                 :          2 :         ffun = mp_make_function_from_proto_fun(proto_fun, context, args);
     244                 :            :     } else {
     245                 :            :         // default positional and keyword args not given
     246                 :       2437 :         ffun = mp_make_function_from_proto_fun(proto_fun, context, NULL);
     247                 :            :     }
     248                 :            :     // wrap function in closure object
     249                 :       2439 :     return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));
     250                 :            : }

Generated by: LCOV version 1.15-5-g462f71d