File: heaptracker.py

package info (click to toggle)
pypy 2.4.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 86,992 kB
  • ctags: 170,715
  • sloc: python: 1,030,417; ansic: 43,437; cpp: 5,241; asm: 5,169; sh: 458; makefile: 408; xml: 231; lisp: 45
file content (127 lines) | stat: -rw-r--r-- 4,753 bytes parent folder | download
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
from rpython.rtyper.lltypesystem import lltype, llmemory, rclass
from rpython.rlib.objectmodel import we_are_translated


def adr2int(addr):
    # Cast an address to an int.  Returns an AddressAsInt object which
    # can be cast back to an address.
    return llmemory.cast_adr_to_int(addr, "symbolic")

def int2adr(int):
    return llmemory.cast_int_to_adr(int)

def count_fields_if_immutable(STRUCT):
    assert isinstance(STRUCT, lltype.GcStruct)
    if STRUCT._hints.get('immutable', False):
        try:
            return _count_fields(STRUCT)
        except ValueError:
            pass
    return -1

def _count_fields(STRUCT):
    if STRUCT == rclass.OBJECT:
        return 0    # don't count 'typeptr'
    result = 0
    for fieldname, TYPE in STRUCT._flds.items():
        if TYPE is lltype.Void:
            pass       # ignore Voids
        elif not isinstance(TYPE, lltype.ContainerType):
            result += 1
        elif isinstance(TYPE, lltype.GcStruct):
            result += _count_fields(TYPE)
        else:
            raise ValueError(TYPE)
    return result

# ____________________________________________________________

def has_gcstruct_a_vtable(GCSTRUCT):
    if not isinstance(GCSTRUCT, lltype.GcStruct):
        return False
    while not GCSTRUCT._hints.get('typeptr'):
        _, GCSTRUCT = GCSTRUCT._first_struct()
        if GCSTRUCT is None:
            return False
    return True

def get_vtable_for_gcstruct(cpu, GCSTRUCT):
    # xxx hack: from a GcStruct representing an instance's
    # lowleveltype, return the corresponding vtable pointer.
    # Returns None if the GcStruct does not belong to an instance.
    assert isinstance(GCSTRUCT, lltype.GcStruct)
    if not has_gcstruct_a_vtable(GCSTRUCT):
        return None
    setup_cache_gcstruct2vtable(cpu)
    return cpu._cache_gcstruct2vtable[GCSTRUCT]

def setup_cache_gcstruct2vtable(cpu):
    if not hasattr(cpu, '_cache_gcstruct2vtable'):
        cache = {}
        cache.update(testing_gcstruct2vtable)
        for rinstance in cpu.rtyper.instance_reprs.values():
            cache[rinstance.lowleveltype.TO] = rinstance.rclass.getvtable()
        cpu._cache_gcstruct2vtable = cache

def set_testing_vtable_for_gcstruct(GCSTRUCT, vtable, name):
    # only for tests that need to register the vtable of their malloc'ed
    # structures in case they are GcStruct inheriting from OBJECT.
    vtable.name = rclass.alloc_array_name(name)
    testing_gcstruct2vtable[GCSTRUCT] = vtable

testing_gcstruct2vtable = {}

# ____________________________________________________________

VTABLETYPE = rclass.CLASSTYPE

def register_known_gctype(cpu, vtable, STRUCT):
    # register the correspondance 'vtable' <-> 'STRUCT' in the cpu
    sizedescr = cpu.sizeof(STRUCT)
    assert sizedescr.as_vtable_size_descr() is sizedescr
    try:
        assert sizedescr._corresponding_vtable == vtable
        return
    except AttributeError:
        pass
    assert lltype.typeOf(vtable) == VTABLETYPE
    if not hasattr(cpu.tracker, '_all_size_descrs_with_vtable'):
        cpu.tracker._all_size_descrs_with_vtable = []
        cpu.tracker._vtable_to_descr_dict = None
    cpu.tracker._all_size_descrs_with_vtable.append(sizedescr)
    sizedescr._corresponding_vtable = vtable

def finish_registering(cpu):
    # annotation hack for small examples which have no vtable at all
    if not hasattr(cpu.tracker, '_all_size_descrs_with_vtable'):
        vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
        register_known_gctype(cpu, vtable, rclass.OBJECT)

def vtable2descr(cpu, vtable):
    assert lltype.typeOf(vtable) is lltype.Signed
    vtable = int2adr(vtable)
    if we_are_translated():
        # Build the dict {vtable: sizedescr} at runtime.
        # This is necessary because the 'vtables' are just pointers to
        # static data, so they can't be used as keys in prebuilt dicts.
        d = cpu.tracker._vtable_to_descr_dict
        if d is None:
            d = cpu.tracker._vtable_to_descr_dict = {}
            for descr in cpu.tracker._all_size_descrs_with_vtable:
                key = descr._corresponding_vtable
                key = llmemory.cast_ptr_to_adr(key)
                d[key] = descr
        return d[vtable]
    else:
        vtable = llmemory.cast_adr_to_ptr(vtable, VTABLETYPE)
        for descr in cpu.tracker._all_size_descrs_with_vtable:
            if descr._corresponding_vtable == vtable:
                return descr
        raise KeyError(vtable)

def descr2vtable(cpu, descr):
    from rpython.jit.metainterp import history
    assert isinstance(descr, history.AbstractDescr)
    vtable = descr.as_vtable_size_descr()._corresponding_vtable
    vtable = llmemory.cast_ptr_to_adr(vtable)
    return adr2int(vtable)