pypy /rpython/jit/backend/zarch/pool.py

Language Python Lines 136
MD5 Hash 334208b0a1acfbc57fb0a336c17baa76 Estimated Cost $2,408 (why?)
Repository https://bitbucket.org/pypy/pypy/ View Raw File View Project SPDX
  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
from rpython.jit.backend.zarch import registers as r
from rpython.jit.backend.zarch import locations as l
from rpython.rlib import rgil
from rpython.jit.metainterp.history import (INT, REF, FLOAT,
        TargetToken)
from rpython.rlib.objectmodel import we_are_translated
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.jit.metainterp.resoperation import rop
from rpython.jit.metainterp.history import Const
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.jit.backend.zarch.arch import (WORD,
        RECOVERY_GCMAP_POOL_OFFSET, RECOVERY_TARGET_POOL_OFFSET)
from rpython.rlib.longlong2float import float2longlong
from rpython.jit.metainterp.history import (ConstFloat,
        ConstInt, ConstPtr)


class PoolOverflow(Exception):
    pass

class LiteralPool(object):
    def __init__(self):
        self.size = 0
        # the offset to index the pool
        self.pool_start = 0
        # for constant offsets
        self.offset_map = {}
        # for descriptors
        self.offset_descr = {}

    def reset(self):
        self.pool_start = 0
        self.size = 0
        self.offset_map = {}
        self.offset_descr = {}

    def ensure_can_hold_constants(self, asm, op):
        # allocates 8 bytes in memory for pointers, long integers or floats
        if rop.is_jit_debug(op.getopnum()):
            return

        for arg in op.getarglist():
            if arg.is_constant():
                self.reserve_literal(8, arg, asm)

    def contains_constant(self, unique_val):
        return unique_val in self.offset_map

    def get_descr_offset(self, descr):
        return self.offset_descr[descr]

    def contains_box(self, box):
        uvalue = self.unique_value(box)
        return self.contains_constant(uvalue)

    def get_offset(self, box):
        assert box.is_constant()
        uvalue = self.unique_value(box)
        if not we_are_translated():
            assert self.offset_map[uvalue] >= 0
        return self.offset_map[uvalue]

    def unique_value(self, val):
        if isinstance(val, ConstFloat):
            if val.getfloat() == 0.0:
                return 0
            return float2longlong(val.getfloat())
        elif isinstance(val, ConstInt):
            return rffi.cast(lltype.Signed, val.getint())
        else:
            assert isinstance(val, ConstPtr)
            return rffi.cast(lltype.Signed, val.getref_base())

    def reserve_literal(self, size, box, asm):
        uvalue = self.unique_value(box)
        if box.type == INT and -2**31 <= uvalue <= 2**31-1:
            # we do not allocate non 64 bit values, these
            # can be loaded as imm by LGHI/LGFI
            return
        #
        self._ensure_value(uvalue, asm)

    def check_size(self, size=-1):
        if size == -1:
            size = self.size
        if size >= 2**19:
            msg = '[S390X/literalpool] size exceeded %d >= %d\n' % (size, 2**19)
            if we_are_translated():
                llop.debug_print(lltype.Void, msg)
            raise PoolOverflow(msg)

    def _ensure_value(self, uvalue, asm):
        if uvalue not in self.offset_map:
            self.offset_map[uvalue] = self.size
            self.allocate_slot(8)
            asm.mc.write_i64(uvalue)
        return self.offset_map[uvalue]

    def allocate_slot(self, size):
        val = self.size + size
        self.check_size(val)
        self.size = val
        assert val >= 0

    def pre_assemble(self, asm, operations, allgcrefs, bridge=False):
        # Problem:
        # constants such as floating point operations, plain pointers,
        # or integers might serve as parameter to an operation. thus
        # it must be loaded into a register. Loading them from immediate
        # takes quite long and slows down the resulting JIT code.
        # There is a space benefit for 64-bit integers/doubles used twice.
        #
        # creates the table for gc references here
        self.gc_table_addr = asm.mc.get_relative_pos()
        self.gcref_table_size = len(allgcrefs) * WORD
        mc = asm.mc
        assert mc.get_relative_pos() == 0
        for i in range(self.gcref_table_size):
            mc.writechar('\x00')
        asm.setup_gcrefs_list(allgcrefs)

        self.pool_start = asm.mc.get_relative_pos()
        for op in operations:
            self.ensure_can_hold_constants(asm, op)
        self._ensure_value(asm.cpu.pos_exc_value(), asm)
        # the top of shadow stack
        gcrootmap = asm.cpu.gc_ll_descr.gcrootmap
        if gcrootmap and gcrootmap.is_shadow_stack:
            self._ensure_value(gcrootmap.get_root_stack_top_addr(), asm)
        # endaddr of insert stack check
        endaddr, lengthaddr, _ = asm.cpu.insert_stack_check()
        self._ensure_value(endaddr, asm)
        # fast gil
        fastgil = rffi.cast(lltype.Signed, rgil.gil_fetch_fastgil())
        self._ensure_value(fastgil, asm)
Back to Top