LCOV - code coverage report
Current view: top level - shared/runtime - gchelper_generic.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-74-g406bccc75.info Lines: 20 20 100.0 %
Date: 2024-12-03 15:10:00 Functions: 2 2 100.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013, 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                 :            : #include <stdio.h>
      28                 :            : 
      29                 :            : #include "py/mpstate.h"
      30                 :            : #include "py/gc.h"
      31                 :            : #include "shared/runtime/gchelper.h"
      32                 :            : 
      33                 :            : #if MICROPY_ENABLE_GC
      34                 :            : 
      35                 :            : // Even if we have specific support for an architecture, it is
      36                 :            : // possible to force use of setjmp-based implementation.
      37                 :            : #if !MICROPY_GCREGS_SETJMP
      38                 :            : 
      39                 :            : // We capture here callee-save registers, i.e. ones which may contain
      40                 :            : // interesting values held there by our callers. It doesn't make sense
      41                 :            : // to capture caller-saved registers, because they, well, put on the
      42                 :            : // stack already by the caller.
      43                 :            : #if defined(__x86_64__)
      44                 :            : 
      45                 :      12893 : static void gc_helper_get_regs(gc_helper_regs_t arr) {
      46                 :      12893 :     register long rbx asm ("rbx");
      47                 :      12893 :     register long rbp asm ("rbp");
      48                 :      12893 :     register long r12 asm ("r12");
      49                 :      12893 :     register long r13 asm ("r13");
      50                 :      12893 :     register long r14 asm ("r14");
      51                 :      12893 :     register long r15 asm ("r15");
      52                 :            :     #ifdef __clang__
      53                 :            :     // TODO:
      54                 :            :     // This is dirty workaround for Clang. It tries to get around
      55                 :            :     // uncompliant (wrt to GCC) behavior of handling register variables.
      56                 :            :     // Application of this patch here is random, and done only to unbreak
      57                 :            :     // MacOS build. Better, cross-arch ways to deal with Clang issues should
      58                 :            :     // be found.
      59                 :            :     asm ("" : "=r" (rbx));
      60                 :            :     asm ("" : "=r" (rbp));
      61                 :            :     asm ("" : "=r" (r12));
      62                 :            :     asm ("" : "=r" (r13));
      63                 :            :     asm ("" : "=r" (r14));
      64                 :            :     asm ("" : "=r" (r15));
      65                 :            :     #endif
      66                 :      12893 :     arr[0] = rbx;
      67                 :      12893 :     arr[1] = rbp;
      68                 :      12893 :     arr[2] = r12;
      69                 :      12893 :     arr[3] = r13;
      70                 :      12893 :     arr[4] = r14;
      71                 :      12893 :     arr[5] = r15;
      72                 :      12893 : }
      73                 :            : 
      74                 :            : #elif defined(__i386__)
      75                 :            : 
      76                 :            : static void gc_helper_get_regs(gc_helper_regs_t arr) {
      77                 :            :     register long ebx asm ("ebx");
      78                 :            :     register long esi asm ("esi");
      79                 :            :     register long edi asm ("edi");
      80                 :            :     register long ebp asm ("ebp");
      81                 :            :     #ifdef __clang__
      82                 :            :     // TODO:
      83                 :            :     // This is dirty workaround for Clang. It tries to get around
      84                 :            :     // uncompliant (wrt to GCC) behavior of handling register variables.
      85                 :            :     // Application of this patch here is random, and done only to unbreak
      86                 :            :     // MacOS build. Better, cross-arch ways to deal with Clang issues should
      87                 :            :     // be found.
      88                 :            :     asm ("" : "=r" (ebx));
      89                 :            :     asm ("" : "=r" (esi));
      90                 :            :     asm ("" : "=r" (edi));
      91                 :            :     asm ("" : "=r" (ebp));
      92                 :            :     #endif
      93                 :            :     arr[0] = ebx;
      94                 :            :     arr[1] = esi;
      95                 :            :     arr[2] = edi;
      96                 :            :     arr[3] = ebp;
      97                 :            : }
      98                 :            : 
      99                 :            : #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
     100                 :            : 
     101                 :            : // Fallback implementation, prefer gchelper_thumb1.s or gchelper_thumb2.s
     102                 :            : 
     103                 :            : static void gc_helper_get_regs(gc_helper_regs_t arr) {
     104                 :            :     register long r4 asm ("r4");
     105                 :            :     register long r5 asm ("r5");
     106                 :            :     register long r6 asm ("r6");
     107                 :            :     register long r7 asm ("r7");
     108                 :            :     register long r8 asm ("r8");
     109                 :            :     register long r9 asm ("r9");
     110                 :            :     register long r10 asm ("r10");
     111                 :            :     register long r11 asm ("r11");
     112                 :            :     register long r12 asm ("r12");
     113                 :            :     register long r13 asm ("r13");
     114                 :            :     arr[0] = r4;
     115                 :            :     arr[1] = r5;
     116                 :            :     arr[2] = r6;
     117                 :            :     arr[3] = r7;
     118                 :            :     arr[4] = r8;
     119                 :            :     arr[5] = r9;
     120                 :            :     arr[6] = r10;
     121                 :            :     arr[7] = r11;
     122                 :            :     arr[8] = r12;
     123                 :            :     arr[9] = r13;
     124                 :            : }
     125                 :            : 
     126                 :            : #elif defined(__aarch64__)
     127                 :            : 
     128                 :            : static void gc_helper_get_regs(gc_helper_regs_t arr) {
     129                 :            :     const register long x19 asm ("x19");
     130                 :            :     const register long x20 asm ("x20");
     131                 :            :     const register long x21 asm ("x21");
     132                 :            :     const register long x22 asm ("x22");
     133                 :            :     const register long x23 asm ("x23");
     134                 :            :     const register long x24 asm ("x24");
     135                 :            :     const register long x25 asm ("x25");
     136                 :            :     const register long x26 asm ("x26");
     137                 :            :     const register long x27 asm ("x27");
     138                 :            :     const register long x28 asm ("x28");
     139                 :            :     const register long x29 asm ("x29");
     140                 :            :     arr[0] = x19;
     141                 :            :     arr[1] = x20;
     142                 :            :     arr[2] = x21;
     143                 :            :     arr[3] = x22;
     144                 :            :     arr[4] = x23;
     145                 :            :     arr[5] = x24;
     146                 :            :     arr[6] = x25;
     147                 :            :     arr[7] = x26;
     148                 :            :     arr[8] = x27;
     149                 :            :     arr[9] = x28;
     150                 :            :     arr[10] = x29;
     151                 :            : }
     152                 :            : 
     153                 :            : #elif defined(__riscv) && (__riscv_xlen <= 64)
     154                 :            : 
     155                 :            : // Fallback implementation for RV32I and RV64I, prefer gchelper_rv32i.s
     156                 :            : // for RV32I targets or gchelper_rv64i.s for RV64I targets.
     157                 :            : 
     158                 :            : static void gc_helper_get_regs(gc_helper_regs_t arr) {
     159                 :            :     register uintptr_t s0 asm ("x8");
     160                 :            :     register uintptr_t s1 asm ("x9");
     161                 :            :     register uintptr_t s2 asm ("x18");
     162                 :            :     register uintptr_t s3 asm ("x19");
     163                 :            :     register uintptr_t s4 asm ("x20");
     164                 :            :     register uintptr_t s5 asm ("x21");
     165                 :            :     register uintptr_t s6 asm ("x22");
     166                 :            :     register uintptr_t s7 asm ("x23");
     167                 :            :     register uintptr_t s8 asm ("x24");
     168                 :            :     register uintptr_t s9 asm ("x25");
     169                 :            :     register uintptr_t s10 asm ("x26");
     170                 :            :     register uintptr_t s11 asm ("x27");
     171                 :            :     arr[0] = s0;
     172                 :            :     arr[1] = s1;
     173                 :            :     arr[2] = s2;
     174                 :            :     arr[3] = s3;
     175                 :            :     arr[4] = s4;
     176                 :            :     arr[5] = s5;
     177                 :            :     arr[6] = s6;
     178                 :            :     arr[7] = s7;
     179                 :            :     arr[8] = s8;
     180                 :            :     arr[9] = s9;
     181                 :            :     arr[10] = s10;
     182                 :            :     arr[11] = s11;
     183                 :            : }
     184                 :            : 
     185                 :            : #else
     186                 :            : 
     187                 :            : #error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation."
     188                 :            : 
     189                 :            : #endif
     190                 :            : 
     191                 :            : #else // !MICROPY_GCREGS_SETJMP
     192                 :            : 
     193                 :            : // Even if we have specific support for an architecture, it is
     194                 :            : // possible to force use of setjmp-based implementation.
     195                 :            : 
     196                 :            : static void gc_helper_get_regs(gc_helper_regs_t arr) {
     197                 :            :     setjmp(arr);
     198                 :            : }
     199                 :            : 
     200                 :            : #endif // MICROPY_GCREGS_SETJMP
     201                 :            : 
     202                 :            : // Explicitly mark this as noinline to make sure the regs variable
     203                 :            : // is effectively at the top of the stack: otherwise, in builds where
     204                 :            : // LTO is enabled and a lot of inlining takes place we risk a stack
     205                 :            : // layout where regs is lower on the stack than pointers which have
     206                 :            : // just been allocated but not yet marked, and get incorrectly sweeped.
     207                 :      12893 : MP_NOINLINE void gc_helper_collect_regs_and_stack(void) {
     208                 :      12893 :     gc_helper_regs_t regs;
     209                 :      12893 :     gc_helper_get_regs(regs);
     210                 :            :     // GC stack (and regs because we captured them)
     211                 :      12893 :     void **regs_ptr = (void **)(void *)&regs;
     212                 :      12893 :     gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)&regs) / sizeof(uintptr_t));
     213                 :      12893 : }
     214                 :            : 
     215                 :            : #endif // MICROPY_ENABLE_GC

Generated by: LCOV version 1.15-5-g462f71d