aboutsummaryrefslogtreecommitdiff
blob: e16f9339e738d87bbad3c28c93ab3693143e4052 (plain)
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
""" 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]

"""

from rpython.rlib import rgc
from rpython.rlib.entrypoint import jit_entrypoint
from rpython.jit.backend.llsupport import asmmemmgr
from rpython.rlib.rbisect import bisect, bisect_tuple
from rpython.rtyper.lltypesystem import lltype, rffi

@jit_entrypoint([lltype.Signed], lltype.Signed,
                c_name='pypy_jit_stack_depth_at_loc')
@rgc.no_collect
def stack_depth_at_loc(loc):
    _memmngr = asmmemmgr._memmngr

    pos = bisect(_memmngr.jit_addr_map, loc)
    if pos == 0 or pos == len(_memmngr.jit_addr_map):
        return -1
    return _memmngr.jit_frame_depth_map[pos-1]

@jit_entrypoint([], lltype.Signed, c_name='pypy_jit_start_addr')
def jit_start_addr():
    _memmngr = asmmemmgr._memmngr

    return _memmngr.jit_addr_map[0]

@jit_entrypoint([], lltype.Signed, c_name='pypy_jit_end_addr')
def jit_end_addr():
    _memmngr = asmmemmgr._memmngr

    return _memmngr.jit_addr_map[-1]

@jit_entrypoint([lltype.Signed], lltype.Signed,
                c_name='pypy_find_codemap_at_addr')
def find_codemap_at_addr(addr):
    _memmngr = asmmemmgr._memmngr

    res = bisect_tuple(_memmngr.jit_codemap, addr) - 1
    if res == len(_memmngr.jit_codemap):
        return -1
    return res

@jit_entrypoint([lltype.Signed, lltype.Signed,
                 rffi.CArrayPtr(lltype.Signed)], lltype.Signed,
                 c_name='pypy_yield_codemap_at_addr')
def yield_bytecode_at_addr(codemap_no, addr, current_pos_addr):
    """ will return consecutive unique_ids from codemap, starting from position
    `pos` until addr
    """
    _memmngr = asmmemmgr._memmngr

    codemap = _memmngr.jit_codemap[codemap_no]
    current_pos = current_pos_addr[0]
    start_addr = codemap[0]
    rel_addr = addr - start_addr
    while True:
        if current_pos >= len(codemap[2]):
            return 0
        next_start = codemap[2][current_pos + 1]
        if next_start > rel_addr:
            return 0
        next_stop = codemap[2][current_pos + 2]
        if next_stop > rel_addr:
            current_pos_addr[0] = current_pos + 4
            return codemap[2][current_pos]
        # we need to skip potentially more than one
        current_pos = codemap[2][current_pos + 3]

def unpack_traceback(addr):
    codemap_pos = find_codemap_at_addr(addr)
    assert codemap_pos >= 0
    storage = lltype.malloc(rffi.CArray(lltype.Signed), 1, flavor='raw')
    storage[0] = 0
    res = []
    while True:
        item = yield_bytecode_at_addr(codemap_pos, addr, storage)
        if item == 0:
            break
        res.append(item)
    lltype.free(storage, flavor='raw')
    return res


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

    def debug_merge_point(self, op, pos):
        call_depth = op.getarg(1).getint()
        if call_depth != self.last_call_depth:
            unique_id = op.getarg(3).getint()
            if unique_id == 0: # uninteresting case
                return
            assert unique_id & 1 == 0
            if call_depth > self.last_call_depth:
                self.l.append(unique_id)
                self.l.append(pos) # <- this is a relative pos
                self.patch_position.append(len(self.l))
                self.l.append(0) # marker
                self.l.append(0) # second marker
            else:
                for i in range(self.last_call_depth - call_depth):
                    to_patch = self.patch_position.pop()
                    self.l[to_patch] = pos
                    self.l[to_patch + 1] = len(self.l)
            self.last_call_depth = call_depth

    def inherit_code_from_position(self, pos):
        lst = unpack_traceback(pos)
        self.last_call_depth = len(lst) - 1
        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
        for i in range(len(self.l) / 4):
            item = self.l[i * 4] # unique_id
            assert item > 0 # no zeros here
            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