File: codemap.py

package info (click to toggle)
pypy 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 107,216 kB
  • sloc: python: 1,201,787; ansic: 62,419; asm: 5,169; cpp: 3,017; sh: 2,534; makefile: 545; xml: 243; lisp: 45; awk: 4
file content (162 lines) | stat: -rw-r--r-- 6,197 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

""" Bytecode for storage in asmmemmgr.jit_codemap. Format is as follows:

 list of tuples of shape (addr, machine code size, bytecode info)
 where bytecode info is a string made up of:
    8 bytes unique_id, 4 bytes start_addr (relative), 4 bytes size (relative),
    2 bytes how many items to skip to go to the next on similar level
    [so far represented by a list of integers for simplicity]

"""

import os
from rpython.rlib import rgc
from rpython.rlib.objectmodel import specialize, we_are_translated
from rpython.rlib.entrypoint import jit_entrypoint
from rpython.rlib.rbisect import bisect_right, bisect_right_addr
from rpython.rlib.rbisect import bisect_left, bisect_left_addr
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator import cdir


INT_LIST_PTR = rffi.CArrayPtr(lltype.Signed)


srcdir = os.path.join(os.path.dirname(__file__), 'src')

libraries = []
if os.name == 'nt':
    libraries.append('Kernel32')

eci = ExternalCompilationInfo(post_include_bits=["""

RPY_EXTERN long pypy_jit_codemap_add(unsigned long addr,
                                     unsigned int machine_code_size,
                                     long *bytecode_info,
                                     unsigned int bytecode_info_size);
RPY_EXTERN long *pypy_jit_codemap_del(unsigned long addr, unsigned int size);
RPY_EXTERN unsigned long pypy_jit_codemap_firstkey(void);
RPY_EXTERN void *pypy_find_codemap_at_addr(long addr, long* start_addr);
RPY_EXTERN long pypy_yield_codemap_at_addr(void *codemap_raw, long addr,
                                           long *current_pos_addr);

"""], separate_module_sources=[
    open(os.path.join(srcdir, 'skiplist.c'), 'r').read() +
    open(os.path.join(srcdir, 'codemap.c'), 'r').read()
], include_dirs=[cdir], libraries=libraries,
compile_extra=['-DPYPY_JIT_CODEMAP'])

def llexternal(name, args, res):
    return rffi.llexternal(name, args, res, compilation_info=eci,
                           releasegil=False)

pypy_jit_codemap_add = llexternal('pypy_jit_codemap_add',
                                  [lltype.Signed, lltype.Signed,
                                   INT_LIST_PTR, lltype.Signed],
                                  lltype.Signed)
pypy_jit_codemap_del = llexternal('pypy_jit_codemap_del',
                                  [lltype.Signed, lltype.Signed], INT_LIST_PTR)
pypy_jit_codemap_firstkey = llexternal('pypy_jit_codemap_firstkey',
                                       [], lltype.Signed)

find_codemap_at_addr = llexternal('pypy_find_codemap_at_addr',
                                 [lltype.Signed, rffi.CArrayPtr(lltype.Signed)],
                                 llmemory.Address)
yield_bytecode_at_addr = llexternal('pypy_yield_codemap_at_addr',
                                    [llmemory.Address, lltype.Signed,
                                     rffi.CArrayPtr(lltype.Signed)],
                                    lltype.Signed)


class CodemapStorage(object):
    """ An immortal wrapper around underlaying jit codemap data
    """
    def setup(self):
        if not we_are_translated():
             # in case someone failed to call free(), in tests only anyway
             self.free()

    def free(self):
        while True:
            key = pypy_jit_codemap_firstkey()
            if not key:
                break
            items = pypy_jit_codemap_del(key, 1)
            lltype.free(items, flavor='raw', track_allocation=False)

    def free_asm_block(self, start, stop):
        items = pypy_jit_codemap_del(start, stop - start)
        if items:
            lltype.free(items, flavor='raw', track_allocation=False)

    def register_codemap(self, (start, size, l)):
        items = lltype.malloc(INT_LIST_PTR.TO, len(l), flavor='raw',
                              track_allocation=False)
        for i in range(len(l)):
            items[i] = l[i]
        if pypy_jit_codemap_add(start, size, items, len(l)) < 0:
            lltype.free(items, flavor='raw', track_allocation=False)

    def finish_once(self):
        self.free()

def unpack_traceback(addr):
    codemap_raw = find_codemap_at_addr(addr,
                                lltype.nullptr(rffi.CArray(lltype.Signed)))
    if not codemap_raw:
        return [] # no codemap for that position
    storage = lltype.malloc(rffi.CArray(lltype.Signed), 1, flavor='raw')
    storage[0] = 0
    res = []
    while True:
        item = yield_bytecode_at_addr(codemap_raw, addr, storage)
        if item == -1:
            break
        res.append(item)
    lltype.free(storage, flavor='raw')
    return res


class CodemapBuilder(object):
    def __init__(self):
        self.l = []
        self.patch_position = []

    def enter_portal_frame(self, jd_id, unique_id, relpos):
        self.l.append(unique_id)
        self.l.append(relpos)
        self.patch_position.append(len(self.l))
        self.l.append(0) # marker
        self.l.append(0) # second marker

    def leave_portal_frame(self, jd_id, relpos):
        if len(self.patch_position) < 1:
            return     # XXX should not occur, but does (issue #2102)
        to_patch = self.patch_position.pop()
        self.l[to_patch] = relpos
        self.l[to_patch + 1] = len(self.l)

    def inherit_code_from_position(self, pos):
        lst = unpack_traceback(pos)
        for item in lst:
            self.l.append(item)
            self.l.append(0)
            self.patch_position.append(len(self.l))
            self.l.append(0) # marker
            self.l.append(0) # second marker

    def get_final_bytecode(self, addr, size):
        while self.patch_position:
            pos = self.patch_position.pop()
            self.l[pos] = size
            self.l[pos + 1] = len(self.l)
        # at the end there should be no zeros, except unique_id which can
        # be zero
        for i in range(len(self.l) / 4):
            item = self.l[i * 4] # unique_id
            item = self.l[i * 4 + 2] # end in asm
            assert item > 0
            item = self.l[i * 4 + 3] # end in l
            assert item > 0
        return (addr, size, self.l) # XXX compact self.l