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 163 164 165 166 167 168 169 170 171 172
|
from rpython.jit.metainterp.history import AbstractDescr, ConstInt
from rpython.jit.codewriter import heaptracker
from rpython.rlib.objectmodel import we_are_translated
class JitCode(AbstractDescr):
_empty_i = []
_empty_r = []
_empty_f = []
def __init__(self, name, fnaddr=None, calldescr=None, called_from=None):
self.name = name
self.fnaddr = fnaddr
self.calldescr = calldescr
self.jitdriver_sd = None # None for non-portals
self._called_from = called_from # debugging
self._ssarepr = None # debugging
def setup(self, code='', constants_i=[], constants_r=[], constants_f=[],
num_regs_i=255, num_regs_r=255, num_regs_f=255,
liveness=None, startpoints=None, alllabels=None,
resulttypes=None):
self.code = code
# if the following lists are empty, use a single shared empty list
self.constants_i = constants_i or self._empty_i
self.constants_r = constants_r or self._empty_r
self.constants_f = constants_f or self._empty_f
# encode the three num_regs into a single char each
assert num_regs_i < 256 and num_regs_r < 256 and num_regs_f < 256
self.c_num_regs_i = chr(num_regs_i)
self.c_num_regs_r = chr(num_regs_r)
self.c_num_regs_f = chr(num_regs_f)
self.liveness = make_liveness_cache(liveness)
self._startpoints = startpoints # debugging
self._alllabels = alllabels # debugging
self._resulttypes = resulttypes # debugging
def get_fnaddr_as_int(self):
return heaptracker.adr2int(self.fnaddr)
def num_regs_i(self):
return ord(self.c_num_regs_i)
def num_regs_r(self):
return ord(self.c_num_regs_r)
def num_regs_f(self):
return ord(self.c_num_regs_f)
def has_liveness_info(self, pc):
return pc in self.liveness
def get_live_vars_info(self, pc):
# 'pc' gives a position in this bytecode. This returns an object
# of class LiveVarsInfo that describes all variables that are live
# across the instruction boundary at 'pc'.
try:
return self.liveness[pc] # XXX compactify!!
except KeyError:
self._missing_liveness(pc)
def _live_vars(self, pc):
# for testing only
info = self.get_live_vars_info(pc)
lst_i = ['%%i%d' % info.get_register_index_i(index)
for index in range(info.get_register_count_i()-1, -1, -1)]
lst_r = ['%%r%d' % info.get_register_index_r(index)
for index in range(info.get_register_count_r()-1, -1, -1)]
lst_f = ['%%f%d' % info.get_register_index_f(index)
for index in range(info.get_register_count_f()-1, -1, -1)]
return ' '.join(lst_i + lst_r + lst_f)
def _missing_liveness(self, pc):
msg = "missing liveness[%d] in %s" % (pc, self.name)
if we_are_translated():
print msg
raise AssertionError
raise MissingLiveness("%s\n%s" % (msg, self.dump()))
def follow_jump(self, position):
"""Assuming that 'position' points just after a bytecode
instruction that ends with a label, follow that label."""
code = self.code
position -= 2
assert position >= 0
if not we_are_translated():
assert position in self._alllabels
labelvalue = ord(code[position]) | (ord(code[position+1])<<8)
assert labelvalue < len(code)
return labelvalue
def dump(self):
if self._ssarepr is None:
return '<no dump available for %r>' % (self.name,)
else:
from rpython.jit.codewriter.format import format_assembler
return format_assembler(self._ssarepr)
def __repr__(self):
return '<JitCode %r>' % self.name
def _clone_if_mutable(self):
raise NotImplementedError
class MissingLiveness(Exception):
pass
class SwitchDictDescr(AbstractDescr):
"Get a 'dict' attribute mapping integer values to bytecode positions."
def attach(self, as_dict):
self.dict = as_dict
self.const_keys_in_order = map(ConstInt, sorted(as_dict.keys()))
def __repr__(self):
dict = getattr(self, 'dict', '?')
return '<SwitchDictDescr %s>' % (dict,)
def _clone_if_mutable(self):
raise NotImplementedError
class LiveVarsInfo(object):
def __init__(self, live_i, live_r, live_f):
self.live_i = live_i
self.live_r = live_r
self.live_f = live_f
def get_register_count_i(self):
return len(self.live_i)
def get_register_count_r(self):
return len(self.live_r)
def get_register_count_f(self):
return len(self.live_f)
def get_register_index_i(self, index):
return ord(self.live_i[index])
def get_register_index_r(self, index):
return ord(self.live_r[index])
def get_register_index_f(self, index):
return ord(self.live_f[index])
def enumerate_vars(self, callback_i, callback_r, callback_f, spec, index):
for i in range(self.get_register_count_i()):
index = callback_i(index, self.get_register_index_i(i))
for i in range(self.get_register_count_r()):
index = callback_r(index, self.get_register_index_r(i))
for i in range(self.get_register_count_f()):
index = callback_f(index, self.get_register_index_f(i))
return index
enumerate_vars._annspecialcase_ = 'specialize:arg(4)'
_liveness_cache = {}
def make_liveness_cache(liveness):
if liveness is None:
return None
result = {}
for key, (value_i, value_r, value_f) in liveness.items():
# Sort the lists to increase the chances of sharing between unrelated
# strings that happen to contain the same characters. We sort in the
# reversed order just to reduce the risks of tests passing by chance.
value = (''.join(sorted(value_i, reverse=True)),
''.join(sorted(value_r, reverse=True)),
''.join(sorted(value_f, reverse=True)))
try:
info = _liveness_cache[value]
except KeyError:
info = _liveness_cache[value] = LiveVarsInfo(*value)
result[key] = info
return result
|