PageRenderTime 99ms CodeModel.GetById 29ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/jit/metainterp/resume.py

https://bitbucket.org/pypy/pypy/
Python | 1317 lines | 1027 code | 184 blank | 106 comment | 191 complexity | a7acd0463da83d7a3cf0a0135d9e3198 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1import sys, os
   2from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind
   3from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
   4from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
   5from pypy.jit.metainterp.history import AbstractDescr
   6from pypy.jit.metainterp.resoperation import rop
   7from pypy.jit.metainterp import jitprof
   8from pypy.jit.codewriter.effectinfo import EffectInfo
   9from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
  10from pypy.rpython import annlowlevel
  11from pypy.rlib import rarithmetic, rstack
  12from pypy.rlib.objectmodel import we_are_translated, specialize
  13from pypy.rlib.debug import have_debug_prints, ll_assert
  14from pypy.rlib.debug import debug_start, debug_stop, debug_print
  15from pypy.jit.metainterp.optimize import InvalidLoop
  16
  17# Logic to encode the chain of frames and the state of the boxes at a
  18# guard operation, and to decode it again.  This is a bit advanced,
  19# because it needs to support optimize.py which encodes virtuals with
  20# arbitrary cycles and also to compress the information
  21
  22class Snapshot(object):
  23    __slots__ = ('prev', 'boxes')
  24
  25    def __init__(self, prev, boxes):
  26        self.prev = prev
  27        self.boxes = boxes
  28
  29class FrameInfo(object):
  30    __slots__ = ('prev', 'jitcode', 'pc')
  31
  32    def __init__(self, prev, jitcode, pc):
  33        self.prev = prev
  34        self.jitcode = jitcode
  35        self.pc = pc
  36
  37def _ensure_parent_resumedata(framestack, n):
  38    target = framestack[n]
  39    if n == 0:
  40        return
  41    back = framestack[n-1]
  42    if target.parent_resumedata_frame_info_list is not None:
  43        assert target.parent_resumedata_frame_info_list.pc == back.pc
  44        return
  45    _ensure_parent_resumedata(framestack, n-1)
  46    target.parent_resumedata_frame_info_list = FrameInfo(
  47                                         back.parent_resumedata_frame_info_list,
  48                                         back.jitcode,
  49                                         back.pc)
  50    target.parent_resumedata_snapshot = Snapshot(
  51                                         back.parent_resumedata_snapshot,
  52                                         back.get_list_of_active_boxes(True))
  53
  54def capture_resumedata(framestack, virtualizable_boxes, virtualref_boxes,
  55                       storage):
  56    n = len(framestack)-1
  57    top = framestack[n]
  58    _ensure_parent_resumedata(framestack, n)
  59    frame_info_list = FrameInfo(top.parent_resumedata_frame_info_list,
  60                                top.jitcode, top.pc)
  61    storage.rd_frame_info_list = frame_info_list
  62    snapshot = Snapshot(top.parent_resumedata_snapshot,
  63                        top.get_list_of_active_boxes(False))
  64    if virtualizable_boxes is not None:
  65        boxes = virtualref_boxes + virtualizable_boxes
  66    else:
  67        boxes = virtualref_boxes[:]
  68    snapshot = Snapshot(snapshot, boxes)
  69    storage.rd_snapshot = snapshot
  70
  71#
  72# The following is equivalent to the RPython-level declaration:
  73#
  74#     class Numbering: __slots__ = ['prev', 'nums']
  75#
  76# except that it is more compact in translated programs, because the
  77# array 'nums' is inlined in the single NUMBERING object.  This is
  78# important because this is often the biggest single consumer of memory
  79# in a pypy-c-jit.
  80#
  81NUMBERINGP = lltype.Ptr(lltype.GcForwardReference())
  82NUMBERING = lltype.GcStruct('Numbering',
  83                            ('prev', NUMBERINGP),
  84                            ('nums', lltype.Array(rffi.SHORT)))
  85NUMBERINGP.TO.become(NUMBERING)
  86
  87PENDINGFIELDSTRUCT = lltype.Struct('PendingField',
  88                                   ('lldescr', annlowlevel.base_ptr_lltype()),
  89                                   ('num', rffi.SHORT),
  90                                   ('fieldnum', rffi.SHORT),
  91                                   ('itemindex', rffi.INT))
  92PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT))
  93
  94TAGMASK = 3
  95
  96class TagOverflow(Exception):
  97    pass
  98
  99def tag(value, tagbits):
 100    assert 0 <= tagbits <= 3
 101    sx = value >> 13
 102    if sx != 0 and sx != -1:
 103        raise TagOverflow
 104    return rffi.r_short(value<<2|tagbits)
 105
 106def untag(value):
 107    value = rarithmetic.widen(value)
 108    tagbits = value&TAGMASK
 109    return value>>2, tagbits
 110
 111def tagged_eq(x, y):
 112    # please rpython :(
 113    return rarithmetic.widen(x) == rarithmetic.widen(y)
 114
 115def tagged_list_eq(tl1, tl2):
 116    if len(tl1) != len(tl2):
 117        return False
 118    for i in range(len(tl1)):
 119        if not tagged_eq(tl1[i], tl2[i]):
 120            return False
 121    return True
 122
 123TAGCONST    = 0
 124TAGINT      = 1
 125TAGBOX      = 2
 126TAGVIRTUAL  = 3
 127
 128UNASSIGNED = tag(-1<<13, TAGBOX)
 129UNASSIGNEDVIRTUAL = tag(-1<<13, TAGVIRTUAL)
 130NULLREF = tag(-1, TAGCONST)
 131UNINITIALIZED = tag(-2, TAGCONST)   # used for uninitialized string characters
 132
 133
 134class ResumeDataLoopMemo(object):
 135
 136    def __init__(self, metainterp_sd):
 137        self.metainterp_sd = metainterp_sd
 138        self.cpu = metainterp_sd.cpu
 139        self.consts = []
 140        self.large_ints = {}
 141        self.refs = self.cpu.ts.new_ref_dict_2()
 142        self.numberings = {}
 143        self.cached_boxes = {}
 144        self.cached_virtuals = {}
 145
 146        self.nvirtuals = 0
 147        self.nvholes = 0
 148        self.nvreused = 0
 149
 150    def getconst(self, const):
 151        if const.type == INT:
 152            val = const.getint()
 153            if not we_are_translated() and not isinstance(val, int):
 154                # unhappiness, probably a symbolic
 155                return self._newconst(const)
 156            try:
 157                return tag(val, TAGINT)
 158            except TagOverflow:
 159                pass
 160            tagged = self.large_ints.get(val, UNASSIGNED)
 161            if not tagged_eq(tagged, UNASSIGNED):
 162                return tagged
 163            tagged = self._newconst(const)
 164            self.large_ints[val] = tagged
 165            return tagged
 166        elif const.type == REF:
 167            val = const.getref_base()
 168            if not val:
 169                return NULLREF
 170            tagged = self.refs.get(val, UNASSIGNED)
 171            if not tagged_eq(tagged, UNASSIGNED):
 172                return tagged
 173            tagged = self._newconst(const)
 174            self.refs[val] = tagged
 175            return tagged
 176        return self._newconst(const)
 177
 178    def _newconst(self, const):
 179        result = tag(len(self.consts), TAGCONST)
 180        self.consts.append(const)
 181        return result
 182
 183    # env numbering
 184
 185    def number(self, values, snapshot):
 186        if snapshot is None:
 187            return lltype.nullptr(NUMBERING), {}, 0
 188        if snapshot in self.numberings:
 189             numb, liveboxes, v = self.numberings[snapshot]
 190             return numb, liveboxes.copy(), v
 191
 192        numb1, liveboxes, v = self.number(values, snapshot.prev)
 193        n = len(liveboxes)-v
 194        boxes = snapshot.boxes
 195        length = len(boxes)
 196        numb = lltype.malloc(NUMBERING, length)
 197        for i in range(length):
 198            box = boxes[i]
 199            value = values.get(box, None)
 200            if value is not None:
 201                box = value.get_key_box()
 202
 203            if isinstance(box, Const):
 204                tagged = self.getconst(box)
 205            elif box in liveboxes:
 206                tagged = liveboxes[box]
 207            else:
 208                if value is not None and value.is_virtual():
 209                    tagged = tag(v, TAGVIRTUAL)
 210                    v += 1
 211                else:
 212                    tagged = tag(n, TAGBOX)
 213                    n += 1
 214                liveboxes[box] = tagged
 215            numb.nums[i] = tagged
 216        #
 217        numb.prev = numb1
 218        self.numberings[snapshot] = numb, liveboxes, v
 219        return numb, liveboxes.copy(), v
 220
 221    def forget_numberings(self, virtualbox):
 222        # XXX ideally clear only the affected numberings
 223        self.numberings.clear()
 224        self.clear_box_virtual_numbers()
 225
 226    # caching for virtuals and boxes inside them
 227
 228    def num_cached_boxes(self):
 229        return len(self.cached_boxes)
 230
 231    def assign_number_to_box(self, box, boxes):
 232        # returns a negative number
 233        if box in self.cached_boxes:
 234            num = self.cached_boxes[box]
 235            boxes[-num-1] = box
 236        else:
 237            boxes.append(box)
 238            num = -len(boxes)
 239            self.cached_boxes[box] = num
 240        return num
 241
 242    def num_cached_virtuals(self):
 243        return len(self.cached_virtuals)
 244
 245    def assign_number_to_virtual(self, box):
 246        # returns a negative number
 247        if box in self.cached_virtuals:
 248            num = self.cached_virtuals[box]
 249        else:
 250            num = self.cached_virtuals[box] = -len(self.cached_virtuals) - 1
 251        return num
 252
 253    def clear_box_virtual_numbers(self):
 254        self.cached_boxes.clear()
 255        self.cached_virtuals.clear()
 256
 257    def update_counters(self, profiler):
 258        profiler.count(jitprof.NVIRTUALS, self.nvirtuals)
 259        profiler.count(jitprof.NVHOLES, self.nvholes)
 260        profiler.count(jitprof.NVREUSED, self.nvreused)
 261
 262_frame_info_placeholder = (None, 0, 0)
 263
 264class ResumeDataVirtualAdder(object):
 265
 266    def __init__(self, storage, memo):
 267        self.storage = storage
 268        self.memo = memo
 269
 270    def make_virtual(self, known_class, fielddescrs):
 271        return VirtualInfo(known_class, fielddescrs)
 272
 273    def make_vstruct(self, typedescr, fielddescrs):
 274        return VStructInfo(typedescr, fielddescrs)
 275
 276    def make_varray(self, arraydescr):
 277        return VArrayInfo(arraydescr)
 278
 279    def make_varraystruct(self, arraydescr, fielddescrs):
 280        return VArrayStructInfo(arraydescr, fielddescrs)
 281
 282    def make_vstrplain(self, is_unicode=False):
 283        if is_unicode:
 284            return VUniPlainInfo()
 285        return VStrPlainInfo()
 286
 287    def make_vstrconcat(self, is_unicode=False):
 288        if is_unicode:
 289            return VUniConcatInfo()
 290        return VStrConcatInfo()
 291
 292    def make_vstrslice(self, is_unicode=False):
 293        if is_unicode:
 294            return VUniSliceInfo()
 295        return VStrSliceInfo()
 296
 297    def register_virtual_fields(self, virtualbox, fieldboxes):
 298        tagged = self.liveboxes_from_env.get(virtualbox, UNASSIGNEDVIRTUAL)
 299        self.liveboxes[virtualbox] = tagged
 300        self.vfieldboxes[virtualbox] = fieldboxes
 301        self._register_boxes(fieldboxes)
 302
 303    def register_box(self, box):
 304        if (isinstance(box, Box) and box not in self.liveboxes_from_env
 305                                 and box not in self.liveboxes):
 306            self.liveboxes[box] = UNASSIGNED
 307
 308    def _register_boxes(self, boxes):
 309        for box in boxes:
 310            self.register_box(box)
 311
 312    def already_seen_virtual(self, virtualbox):
 313        if virtualbox not in self.liveboxes:
 314            assert virtualbox in self.liveboxes_from_env
 315            assert untag(self.liveboxes_from_env[virtualbox])[1] == TAGVIRTUAL
 316            return False
 317        tagged = self.liveboxes[virtualbox]
 318        _, tagbits = untag(tagged)
 319        return tagbits == TAGVIRTUAL
 320
 321    def finish(self, values, pending_setfields=[]):
 322        # compute the numbering
 323        storage = self.storage
 324        # make sure that nobody attached resume data to this guard yet
 325        assert not storage.rd_numb
 326        snapshot = storage.rd_snapshot
 327        assert snapshot is not None # is that true?
 328        numb, liveboxes_from_env, v = self.memo.number(values, snapshot)
 329        self.liveboxes_from_env = liveboxes_from_env
 330        self.liveboxes = {}
 331        storage.rd_numb = numb
 332        storage.rd_snapshot = None
 333
 334        # collect liveboxes and virtuals
 335        n = len(liveboxes_from_env) - v
 336        liveboxes = [None]*n
 337        self.vfieldboxes = {}
 338        for box, tagged in liveboxes_from_env.iteritems():
 339            i, tagbits = untag(tagged)
 340            if tagbits == TAGBOX:
 341                liveboxes[i] = box
 342            else:
 343                assert tagbits == TAGVIRTUAL
 344                value = values[box]
 345                value.get_args_for_fail(self)
 346
 347        for _, box, fieldbox, _ in pending_setfields:
 348            self.register_box(box)
 349            self.register_box(fieldbox)
 350            value = values[fieldbox]
 351            value.get_args_for_fail(self)
 352
 353        self._number_virtuals(liveboxes, values, v)
 354        self._add_pending_fields(pending_setfields)
 355
 356        storage.rd_consts = self.memo.consts
 357        dump_storage(storage, liveboxes)
 358        return liveboxes[:]
 359
 360    def _number_virtuals(self, liveboxes, values, num_env_virtuals):
 361        # !! 'liveboxes' is a list that is extend()ed in-place !!
 362        memo = self.memo
 363        new_liveboxes = [None] * memo.num_cached_boxes()
 364        count = 0
 365        # So far, self.liveboxes should contain 'tagged' values that are
 366        # either UNASSIGNED, UNASSIGNEDVIRTUAL, or a *non-negative* value
 367        # with the TAGVIRTUAL.  The following loop removes the UNASSIGNED
 368        # and UNASSIGNEDVIRTUAL entries, and replaces them with real
 369        # negative values.
 370        for box, tagged in self.liveboxes.iteritems():
 371            i, tagbits = untag(tagged)
 372            if tagbits == TAGBOX:
 373                assert box not in self.liveboxes_from_env
 374                assert tagged_eq(tagged, UNASSIGNED)
 375                index = memo.assign_number_to_box(box, new_liveboxes)
 376                self.liveboxes[box] = tag(index, TAGBOX)
 377                count += 1
 378            else:
 379                assert tagbits == TAGVIRTUAL
 380                if tagged_eq(tagged, UNASSIGNEDVIRTUAL):
 381                    assert box not in self.liveboxes_from_env
 382                    index = memo.assign_number_to_virtual(box)
 383                    self.liveboxes[box] = tag(index, TAGVIRTUAL)
 384                else:
 385                    assert i >= 0
 386        new_liveboxes.reverse()
 387        liveboxes.extend(new_liveboxes)
 388        nholes = len(new_liveboxes) - count
 389
 390        storage = self.storage
 391        storage.rd_virtuals = None
 392        vfieldboxes = self.vfieldboxes
 393        if vfieldboxes:
 394            length = num_env_virtuals + memo.num_cached_virtuals()
 395            virtuals = storage.rd_virtuals = [None] * length
 396            memo.nvirtuals += length
 397            memo.nvholes += length - len(vfieldboxes)
 398            for virtualbox, fieldboxes in vfieldboxes.iteritems():
 399                num, _ = untag(self.liveboxes[virtualbox])
 400                value = values[virtualbox]
 401                fieldnums = [self._gettagged(box)
 402                             for box in fieldboxes]
 403                vinfo = value.make_virtual_info(self, fieldnums)
 404                # if a new vinfo instance is made, we get the fieldnums list we
 405                # pass in as an attribute. hackish.
 406                if vinfo.fieldnums is not fieldnums:
 407                    memo.nvreused += 1
 408                virtuals[num] = vinfo
 409
 410        if self._invalidation_needed(len(liveboxes), nholes):
 411            memo.clear_box_virtual_numbers()
 412
 413    def _invalidation_needed(self, nliveboxes, nholes):
 414        memo = self.memo
 415        # xxx heuristic a bit out of thin air
 416        failargs_limit = memo.metainterp_sd.options.failargs_limit
 417        if nliveboxes > (failargs_limit // 2):
 418            if nholes > nliveboxes//3:
 419                return True
 420        return False
 421
 422    def _add_pending_fields(self, pending_setfields):
 423        rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
 424        if pending_setfields:
 425            n = len(pending_setfields)
 426            rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n)
 427            for i in range(n):
 428                descr, box, fieldbox, itemindex = pending_setfields[i]
 429                lldescr = annlowlevel.cast_instance_to_base_ptr(descr)
 430                num = self._gettagged(box)
 431                fieldnum = self._gettagged(fieldbox)
 432                # the index is limited to 2147483647 (64-bit machines only)
 433                if itemindex > 2147483647:
 434                    raise TagOverflow
 435                itemindex = rffi.cast(rffi.INT, itemindex)
 436                #
 437                rd_pendingfields[i].lldescr  = lldescr
 438                rd_pendingfields[i].num      = num
 439                rd_pendingfields[i].fieldnum = fieldnum
 440                rd_pendingfields[i].itemindex= itemindex
 441        self.storage.rd_pendingfields = rd_pendingfields
 442
 443    def _gettagged(self, box):
 444        if box is None:
 445            return UNINITIALIZED
 446        if isinstance(box, Const):
 447            return self.memo.getconst(box)
 448        else:
 449            if box in self.liveboxes_from_env:
 450                return self.liveboxes_from_env[box]
 451            return self.liveboxes[box]
 452
 453
 454class AbstractVirtualInfo(object):
 455    #def allocate(self, decoder, index):
 456    #    raise NotImplementedError
 457    def equals(self, fieldnums):
 458        return tagged_list_eq(self.fieldnums, fieldnums)
 459
 460    def set_content(self, fieldnums):
 461        self.fieldnums = fieldnums
 462
 463    def debug_prints(self):
 464        raise NotImplementedError
 465
 466class AbstractVirtualStructInfo(AbstractVirtualInfo):
 467    def __init__(self, fielddescrs):
 468        self.fielddescrs = fielddescrs
 469        #self.fieldnums = ...
 470
 471    @specialize.argtype(1)
 472    def setfields(self, decoder, struct):
 473        for i in range(len(self.fielddescrs)):
 474            descr = self.fielddescrs[i]
 475            decoder.setfield(descr, struct, self.fieldnums[i])
 476        return struct
 477
 478    def debug_prints(self):
 479        assert len(self.fielddescrs) == len(self.fieldnums)
 480        for i in range(len(self.fielddescrs)):
 481            debug_print("\t\t",
 482                        str(self.fielddescrs[i]),
 483                        str(untag(self.fieldnums[i])))
 484
 485class VirtualInfo(AbstractVirtualStructInfo):
 486    def __init__(self, known_class, fielddescrs):
 487        AbstractVirtualStructInfo.__init__(self, fielddescrs)
 488        self.known_class = known_class
 489
 490    @specialize.argtype(1)
 491    def allocate(self, decoder, index):
 492        struct = decoder.allocate_with_vtable(self.known_class)
 493        decoder.virtuals_cache[index] = struct
 494        return self.setfields(decoder, struct)
 495
 496    def debug_prints(self):
 497        debug_print("\tvirtualinfo", self.known_class.repr_rpython())
 498        AbstractVirtualStructInfo.debug_prints(self)
 499
 500
 501class VStructInfo(AbstractVirtualStructInfo):
 502    def __init__(self, typedescr, fielddescrs):
 503        AbstractVirtualStructInfo.__init__(self, fielddescrs)
 504        self.typedescr = typedescr
 505
 506    @specialize.argtype(1)
 507    def allocate(self, decoder, index):
 508        struct = decoder.allocate_struct(self.typedescr)
 509        decoder.virtuals_cache[index] = struct
 510        return self.setfields(decoder, struct)
 511
 512    def debug_prints(self):
 513        debug_print("\tvstructinfo", self.typedescr.repr_rpython())
 514        AbstractVirtualStructInfo.debug_prints(self)
 515
 516class VArrayInfo(AbstractVirtualInfo):
 517    def __init__(self, arraydescr):
 518        self.arraydescr = arraydescr
 519        #self.fieldnums = ...
 520
 521    @specialize.argtype(1)
 522    def allocate(self, decoder, index):
 523        length = len(self.fieldnums)
 524        arraydescr = self.arraydescr
 525        array = decoder.allocate_array(arraydescr, length)
 526        decoder.virtuals_cache[index] = array
 527        # NB. the check for the kind of array elements is moved out of the loop
 528        if arraydescr.is_array_of_pointers():
 529            for i in range(length):
 530                decoder.setarrayitem_ref(arraydescr, array, i,
 531                                         self.fieldnums[i])
 532        elif arraydescr.is_array_of_floats():
 533            for i in range(length):
 534                decoder.setarrayitem_float(arraydescr, array, i,
 535                                           self.fieldnums[i])
 536        else:
 537            for i in range(length):
 538                decoder.setarrayitem_int(arraydescr, array, i,
 539                                         self.fieldnums[i])
 540        return array
 541
 542    def debug_prints(self):
 543        debug_print("\tvarrayinfo", self.arraydescr)
 544        for i in self.fieldnums:
 545            debug_print("\t\t", str(untag(i)))
 546
 547
 548class VArrayStructInfo(AbstractVirtualInfo):
 549    def __init__(self, arraydescr, fielddescrs):
 550        self.arraydescr = arraydescr
 551        self.fielddescrs = fielddescrs
 552
 553    def debug_prints(self):
 554        debug_print("\tvarraystructinfo", self.arraydescr)
 555        for i in self.fieldnums:
 556            debug_print("\t\t", str(untag(i)))
 557
 558    @specialize.argtype(1)
 559    def allocate(self, decoder, index):
 560        array = decoder.allocate_array(self.arraydescr, len(self.fielddescrs))
 561        decoder.virtuals_cache[index] = array
 562        p = 0
 563        for i in range(len(self.fielddescrs)):
 564            for j in range(len(self.fielddescrs[i])):
 565                decoder.setinteriorfield(i, self.fielddescrs[i][j], array, self.fieldnums[p])
 566                p += 1
 567        return array
 568
 569
 570class VStrPlainInfo(AbstractVirtualInfo):
 571    """Stands for the string made out of the characters of all fieldnums."""
 572
 573    @specialize.argtype(1)
 574    def allocate(self, decoder, index):
 575        length = len(self.fieldnums)
 576        string = decoder.allocate_string(length)
 577        decoder.virtuals_cache[index] = string
 578        for i in range(length):
 579            charnum = self.fieldnums[i]
 580            if not tagged_eq(charnum, UNINITIALIZED):
 581                decoder.string_setitem(string, i, charnum)
 582        return string
 583
 584    def debug_prints(self):
 585        debug_print("\tvstrplaininfo length", len(self.fieldnums))
 586
 587
 588class VStrConcatInfo(AbstractVirtualInfo):
 589    """Stands for the string made out of the concatenation of two
 590    other strings."""
 591
 592    @specialize.argtype(1)
 593    def allocate(self, decoder, index):
 594        # xxx for blackhole resuming, this will build all intermediate
 595        # strings and throw them away immediately, which is a bit sub-
 596        # efficient.  Not sure we care.
 597        left, right = self.fieldnums
 598        string = decoder.concat_strings(left, right)
 599        decoder.virtuals_cache[index] = string
 600        return string
 601
 602    def debug_prints(self):
 603        debug_print("\tvstrconcatinfo")
 604        for i in self.fieldnums:
 605            debug_print("\t\t", str(untag(i)))
 606
 607
 608class VStrSliceInfo(AbstractVirtualInfo):
 609    """Stands for the string made out of slicing another string."""
 610
 611    @specialize.argtype(1)
 612    def allocate(self, decoder, index):
 613        largerstr, start, length = self.fieldnums
 614        string = decoder.slice_string(largerstr, start, length)
 615        decoder.virtuals_cache[index] = string
 616        return string
 617
 618    def debug_prints(self):
 619        debug_print("\tvstrsliceinfo")
 620        for i in self.fieldnums:
 621            debug_print("\t\t", str(untag(i)))
 622
 623
 624class VUniPlainInfo(AbstractVirtualInfo):
 625    """Stands for the unicode string made out of the characters of all
 626    fieldnums."""
 627
 628    @specialize.argtype(1)
 629    def allocate(self, decoder, index):
 630        length = len(self.fieldnums)
 631        string = decoder.allocate_unicode(length)
 632        decoder.virtuals_cache[index] = string
 633        for i in range(length):
 634            charnum = self.fieldnums[i]
 635            if not tagged_eq(charnum, UNINITIALIZED):
 636                decoder.unicode_setitem(string, i, charnum)
 637        return string
 638
 639    def debug_prints(self):
 640        debug_print("\tvuniplaininfo length", len(self.fieldnums))
 641
 642
 643class VUniConcatInfo(AbstractVirtualInfo):
 644    """Stands for the unicode string made out of the concatenation of two
 645    other unicode strings."""
 646
 647    @specialize.argtype(1)
 648    def allocate(self, decoder, index):
 649        # xxx for blackhole resuming, this will build all intermediate
 650        # strings and throw them away immediately, which is a bit sub-
 651        # efficient.  Not sure we care.
 652        left, right = self.fieldnums
 653        string = decoder.concat_unicodes(left, right)
 654        decoder.virtuals_cache[index] = string
 655        return string
 656
 657    def debug_prints(self):
 658        debug_print("\tvuniconcatinfo")
 659        for i in self.fieldnums:
 660            debug_print("\t\t", str(untag(i)))
 661
 662
 663class VUniSliceInfo(AbstractVirtualInfo):
 664    """Stands for the unicode string made out of slicing another
 665    unicode string."""
 666
 667    @specialize.argtype(1)
 668    def allocate(self, decoder, index):
 669        largerstr, start, length = self.fieldnums
 670        string = decoder.slice_unicode(largerstr, start, length)
 671        decoder.virtuals_cache[index] = string
 672        return string
 673
 674    def debug_prints(self):
 675        debug_print("\tvunisliceinfo")
 676        for i in self.fieldnums:
 677            debug_print("\t\t", str(untag(i)))
 678
 679# ____________________________________________________________
 680
 681class AbstractResumeDataReader(object):
 682    """A base mixin containing the logic to reconstruct virtuals out of
 683    guard failure.  There are two implementations of this mixin:
 684    ResumeDataBoxReader for when we are compiling (i.e. when we have a
 685    metainterp), and ResumeDataDirectReader for when we are merely
 686    blackholing and want the best performance.
 687    """
 688    _mixin_ = True
 689    rd_virtuals = None
 690    virtuals_cache = None
 691    virtual_default = None
 692
 693    def _init(self, cpu, storage):
 694        self.cpu = cpu
 695        self.cur_numb = storage.rd_numb
 696        self.consts = storage.rd_consts
 697
 698    def _prepare(self, storage):
 699        self._prepare_virtuals(storage.rd_virtuals)
 700        self._prepare_pendingfields(storage.rd_pendingfields)
 701
 702    def getvirtual(self, index):
 703        # Returns the index'th virtual, building it lazily if needed.
 704        # Note that this may be called recursively; that's why the
 705        # allocate() methods must fill in the cache as soon as they
 706        # have the object, before they fill its fields.
 707        assert self.virtuals_cache is not None
 708        v = self.virtuals_cache[index]
 709        if not v:
 710            v = self.rd_virtuals[index].allocate(self, index)
 711            ll_assert(v == self.virtuals_cache[index], "resume.py: bad cache")
 712        return v
 713
 714    def force_all_virtuals(self):
 715        rd_virtuals = self.rd_virtuals
 716        if rd_virtuals:
 717            for i in range(len(rd_virtuals)):
 718                if rd_virtuals[i] is not None:
 719                    self.getvirtual(i)
 720        return self.virtuals_cache
 721
 722    def _prepare_virtuals(self, virtuals):
 723        if virtuals:
 724            self.rd_virtuals = virtuals
 725            self.virtuals_cache = [self.virtual_default] * len(virtuals)
 726
 727    def _prepare_pendingfields(self, pendingfields):
 728        if pendingfields:
 729            for i in range(len(pendingfields)):
 730                lldescr  = pendingfields[i].lldescr
 731                num      = pendingfields[i].num
 732                fieldnum = pendingfields[i].fieldnum
 733                itemindex= pendingfields[i].itemindex
 734                descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr,
 735                                                              lldescr)
 736                struct = self.decode_ref(num)
 737                itemindex = rffi.cast(lltype.Signed, itemindex)
 738                if itemindex < 0:
 739                    self.setfield(descr, struct, fieldnum)
 740                else:
 741                    self.setarrayitem(descr, struct, itemindex, fieldnum)
 742
 743    def setarrayitem(self, arraydescr, array, index, fieldnum):
 744        if arraydescr.is_array_of_pointers():
 745            self.setarrayitem_ref(arraydescr, array, index, fieldnum)
 746        elif arraydescr.is_array_of_floats():
 747            self.setarrayitem_float(arraydescr, array, index, fieldnum)
 748        else:
 749            self.setarrayitem_int(arraydescr, array, index, fieldnum)
 750
 751    def _prepare_next_section(self, info):
 752        # Use info.enumerate_vars(), normally dispatching to
 753        # pypy.jit.codewriter.jitcode.  Some tests give a different 'info'.
 754        info.enumerate_vars(self._callback_i,
 755                            self._callback_r,
 756                            self._callback_f,
 757                            self.unique_id)    # <-- annotation hack
 758        self.cur_numb = self.cur_numb.prev
 759
 760    def _callback_i(self, index, register_index):
 761        value = self.decode_int(self.cur_numb.nums[index])
 762        self.write_an_int(register_index, value)
 763
 764    def _callback_r(self, index, register_index):
 765        value = self.decode_ref(self.cur_numb.nums[index])
 766        self.write_a_ref(register_index, value)
 767
 768    def _callback_f(self, index, register_index):
 769        value = self.decode_float(self.cur_numb.nums[index])
 770        self.write_a_float(register_index, value)
 771
 772    def done(self):
 773        self.cpu.clear_latest_values(self.cpu.get_latest_value_count())
 774
 775# ---------- when resuming for pyjitpl.py, make boxes ----------
 776
 777def rebuild_from_resumedata(metainterp, storage, virtualizable_info,
 778                            greenfield_info):
 779    resumereader = ResumeDataBoxReader(storage, metainterp)
 780    boxes = resumereader.consume_vref_and_vable_boxes(virtualizable_info,
 781                                                      greenfield_info)
 782    virtualizable_boxes, virtualref_boxes = boxes
 783    frameinfo = storage.rd_frame_info_list
 784    while True:
 785        f = metainterp.newframe(frameinfo.jitcode)
 786        f.setup_resume_at_op(frameinfo.pc)
 787        resumereader.consume_boxes(f.get_current_position_info(),
 788                                   f.registers_i, f.registers_r, f.registers_f)
 789        frameinfo = frameinfo.prev
 790        if frameinfo is None:
 791            break
 792    metainterp.framestack.reverse()
 793    resumereader.done()
 794    return resumereader.liveboxes, virtualizable_boxes, virtualref_boxes
 795
 796class ResumeDataBoxReader(AbstractResumeDataReader):
 797    unique_id = lambda: None
 798
 799    def __init__(self, storage, metainterp):
 800        self._init(metainterp.cpu, storage)
 801        self.metainterp = metainterp
 802        self.liveboxes = [None] * metainterp.cpu.get_latest_value_count()
 803        self._prepare(storage)
 804
 805    def consume_boxes(self, info, boxes_i, boxes_r, boxes_f):
 806        self.boxes_i = boxes_i
 807        self.boxes_r = boxes_r
 808        self.boxes_f = boxes_f
 809        self._prepare_next_section(info)
 810
 811    def consume_virtualizable_boxes(self, vinfo, numb):
 812        # we have to ignore the initial part of 'nums' (containing vrefs),
 813        # find the virtualizable from nums[-1], and use it to know how many
 814        # boxes of which type we have to return.  This does not write
 815        # anything into the virtualizable.
 816        index = len(numb.nums) - 1
 817        virtualizablebox = self.decode_ref(numb.nums[index])
 818        virtualizable = vinfo.unwrap_virtualizable_box(virtualizablebox)
 819        return vinfo.load_list_of_boxes(virtualizable, self, numb)
 820
 821    def consume_virtualref_boxes(self, numb, end):
 822        # Returns a list of boxes, assumed to be all BoxPtrs.
 823        # We leave up to the caller to call vrefinfo.continue_tracing().
 824        assert (end & 1) == 0
 825        return [self.decode_ref(numb.nums[i]) for i in range(end)]
 826
 827    def consume_vref_and_vable_boxes(self, vinfo, ginfo):
 828        numb = self.cur_numb
 829        self.cur_numb = numb.prev
 830        if vinfo is not None:
 831            virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, numb)
 832            end = len(numb.nums) - len(virtualizable_boxes)
 833        elif ginfo is not None:
 834            index = len(numb.nums) - 1
 835            virtualizable_boxes = [self.decode_ref(numb.nums[index])]
 836            end = len(numb.nums) - 1
 837        else:
 838            virtualizable_boxes = None
 839            end = len(numb.nums)
 840        virtualref_boxes = self.consume_virtualref_boxes(numb, end)
 841        return virtualizable_boxes, virtualref_boxes
 842
 843    def allocate_with_vtable(self, known_class):
 844        return self.metainterp.execute_and_record(rop.NEW_WITH_VTABLE,
 845                                                  None, known_class)
 846
 847    def allocate_struct(self, typedescr):
 848        return self.metainterp.execute_and_record(rop.NEW, typedescr)
 849
 850    def allocate_array(self, arraydescr, length):
 851        return self.metainterp.execute_and_record(rop.NEW_ARRAY,
 852                                                  arraydescr, ConstInt(length))
 853
 854    def allocate_string(self, length):
 855        return self.metainterp.execute_and_record(rop.NEWSTR,
 856                                                  None, ConstInt(length))
 857
 858    def string_setitem(self, strbox, index, charnum):
 859        charbox = self.decode_box(charnum, INT)
 860        self.metainterp.execute_and_record(rop.STRSETITEM, None,
 861                                           strbox, ConstInt(index), charbox)
 862
 863    def concat_strings(self, str1num, str2num):
 864        cic = self.metainterp.staticdata.callinfocollection
 865        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
 866        str1box = self.decode_box(str1num, REF)
 867        str2box = self.decode_box(str2num, REF)
 868        return self.metainterp.execute_and_record_varargs(
 869            rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
 870
 871    def slice_string(self, strnum, startnum, lengthnum):
 872        cic = self.metainterp.staticdata.callinfocollection
 873        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
 874        strbox = self.decode_box(strnum, REF)
 875        startbox = self.decode_box(startnum, INT)
 876        lengthbox = self.decode_box(lengthnum, INT)
 877        stopbox = self.metainterp.execute_and_record(rop.INT_ADD, None,
 878                                                     startbox, lengthbox)
 879        return self.metainterp.execute_and_record_varargs(
 880            rop.CALL, [ConstInt(func), strbox, startbox, stopbox], calldescr)
 881
 882    def allocate_unicode(self, length):
 883        return self.metainterp.execute_and_record(rop.NEWUNICODE,
 884                                                  None, ConstInt(length))
 885
 886    def unicode_setitem(self, strbox, index, charnum):
 887        charbox = self.decode_box(charnum, INT)
 888        self.metainterp.execute_and_record(rop.UNICODESETITEM, None,
 889                                           strbox, ConstInt(index), charbox)
 890
 891    def concat_unicodes(self, str1num, str2num):
 892        cic = self.metainterp.staticdata.callinfocollection
 893        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
 894        str1box = self.decode_box(str1num, REF)
 895        str2box = self.decode_box(str2num, REF)
 896        return self.metainterp.execute_and_record_varargs(
 897            rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
 898
 899    def slice_unicode(self, strnum, startnum, lengthnum):
 900        cic = self.metainterp.staticdata.callinfocollection
 901        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
 902        strbox = self.decode_box(strnum, REF)
 903        startbox = self.decode_box(startnum, INT)
 904        lengthbox = self.decode_box(lengthnum, INT)
 905        stopbox = self.metainterp.execute_and_record(rop.INT_ADD, None,
 906                                                     startbox, lengthbox)
 907        return self.metainterp.execute_and_record_varargs(
 908            rop.CALL, [ConstInt(func), strbox, startbox, stopbox], calldescr)
 909
 910    def setfield(self, descr, structbox, fieldnum):
 911        if descr.is_pointer_field():
 912            kind = REF
 913        elif descr.is_float_field():
 914            kind = FLOAT
 915        else:
 916            kind = INT
 917        fieldbox = self.decode_box(fieldnum, kind)
 918        self.metainterp.execute_and_record(rop.SETFIELD_GC, descr,
 919                                           structbox, fieldbox)
 920
 921    def setinteriorfield(self, index, descr, array, fieldnum):
 922        if descr.is_pointer_field():
 923            kind = REF
 924        elif descr.is_float_field():
 925            kind = FLOAT
 926        else:
 927            kind = INT
 928        fieldbox = self.decode_box(fieldnum, kind)
 929        self.metainterp.execute_and_record(rop.SETINTERIORFIELD_GC, descr,
 930                                           array, ConstInt(index), fieldbox)
 931
 932    def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum):
 933        self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT)
 934
 935    def setarrayitem_ref(self, arraydescr, arraybox, index, fieldnum):
 936        self._setarrayitem(arraydescr, arraybox, index, fieldnum, REF)
 937
 938    def setarrayitem_float(self, arraydescr, arraybox, index, fieldnum):
 939        self._setarrayitem(arraydescr, arraybox, index, fieldnum, FLOAT)
 940
 941    def _setarrayitem(self, arraydescr, arraybox, index, fieldnum, kind):
 942        itembox = self.decode_box(fieldnum, kind)
 943        self.metainterp.execute_and_record(rop.SETARRAYITEM_GC,
 944                                           arraydescr, arraybox,
 945                                           ConstInt(index), itembox)
 946
 947    def decode_int(self, tagged):
 948        return self.decode_box(tagged, INT)
 949    def decode_ref(self, tagged):
 950        return self.decode_box(tagged, REF)
 951    def decode_float(self, tagged):
 952        return self.decode_box(tagged, FLOAT)
 953
 954    def decode_box(self, tagged, kind):
 955        num, tag = untag(tagged)
 956        if tag == TAGCONST:
 957            if tagged_eq(tagged, NULLREF):
 958                box = self.cpu.ts.CONST_NULL
 959            else:
 960                box = self.consts[num]
 961        elif tag == TAGVIRTUAL:
 962            box = self.getvirtual(num)
 963        elif tag == TAGINT:
 964            box = ConstInt(num)
 965        else:
 966            assert tag == TAGBOX
 967            box = self.liveboxes[num]
 968            if box is None:
 969                box = self.load_box_from_cpu(num, kind)
 970        assert box.type == kind
 971        return box
 972
 973    def load_box_from_cpu(self, num, kind):
 974        if num < 0:
 975            num += len(self.liveboxes)
 976            assert num >= 0
 977        if kind == INT:
 978            box = BoxInt(self.cpu.get_latest_value_int(num))
 979        elif kind == REF:
 980            box = BoxPtr(self.cpu.get_latest_value_ref(num))
 981        elif kind == FLOAT:
 982            box = BoxFloat(self.cpu.get_latest_value_float(num))
 983        else:
 984            assert 0, "bad kind: %d" % ord(kind)
 985        self.liveboxes[num] = box
 986        return box
 987
 988    def decode_box_of_type(self, TYPE, tagged):
 989        kind = getkind(TYPE)
 990        if kind == 'int':     kind = INT
 991        elif kind == 'ref':   kind = REF
 992        elif kind == 'float': kind = FLOAT
 993        else: raise AssertionError(kind)
 994        return self.decode_box(tagged, kind)
 995    decode_box_of_type._annspecialcase_ = 'specialize:arg(1)'
 996
 997    def write_an_int(self, index, box):
 998        self.boxes_i[index] = box
 999    def write_a_ref(self, index, box):
1000        self.boxes_r[index] = box
1001    def write_a_float(self, index, box):
1002        self.boxes_f[index] = box
1003
1004# ---------- when resuming for blackholing, get direct values ----------
1005
1006def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
1007                              all_virtuals=None):
1008    # The initialization is stack-critical code: it must not be interrupted by
1009    # StackOverflow, otherwise the jit_virtual_refs are left in a dangling state.
1010    rstack._stack_criticalcode_start()
1011    try:
1012        resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
1013                                              storage, all_virtuals)
1014        vinfo = jitdriver_sd.virtualizable_info
1015        ginfo = jitdriver_sd.greenfield_info
1016        vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
1017        resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
1018    finally:
1019        rstack._stack_criticalcode_stop()
1020    #
1021    # First get a chain of blackhole interpreters whose length is given
1022    # by the depth of rd_frame_info_list.  The first one we get must be
1023    # the bottom one, i.e. the last one in the chain, in order to make
1024    # the comment in BlackholeInterpreter.setposition() valid.
1025    nextbh = None
1026    frameinfo = storage.rd_frame_info_list
1027    while True:
1028        curbh = blackholeinterpbuilder.acquire_interp()
1029        curbh.nextblackholeinterp = nextbh
1030        nextbh = curbh
1031        frameinfo = frameinfo.prev
1032        if frameinfo is None:
1033            break
1034    firstbh = nextbh
1035    #
1036    # Now fill the blackhole interpreters with resume data.
1037    curbh = firstbh
1038    frameinfo = storage.rd_frame_info_list
1039    while True:
1040        curbh.setposition(frameinfo.jitcode, frameinfo.pc)
1041        resumereader.consume_one_section(curbh)
1042        curbh = curbh.nextblackholeinterp
1043        frameinfo = frameinfo.prev
1044        if frameinfo is None:
1045            break
1046    resumereader.done()
1047    return firstbh
1048
1049def force_from_resumedata(metainterp_sd, storage, vinfo, ginfo):
1050    resumereader = ResumeDataDirectReader(metainterp_sd, storage)
1051    resumereader.handling_async_forcing()
1052    vrefinfo = metainterp_sd.virtualref_info
1053    resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
1054    return resumereader.force_all_virtuals()
1055
1056class ResumeDataDirectReader(AbstractResumeDataReader):
1057    unique_id = lambda: None
1058    virtual_default = lltype.nullptr(llmemory.GCREF.TO)
1059    resume_after_guard_not_forced = 0
1060    #             0: not a GUARD_NOT_FORCED
1061    #             1: in handle_async_forcing
1062    #             2: resuming from the GUARD_NOT_FORCED
1063
1064    def __init__(self, metainterp_sd, storage, all_virtuals=None):
1065        self._init(metainterp_sd.cpu, storage)
1066        self.callinfocollection = metainterp_sd.callinfocollection
1067        if all_virtuals is None:        # common case
1068            self._prepare(storage)
1069        else:
1070            # special case for resuming after a GUARD_NOT_FORCED: we already
1071            # have the virtuals
1072            self.resume_after_guard_not_forced = 2
1073            self.virtuals_cache = all_virtuals
1074            # self.rd_virtuals can remain None, because virtuals_cache is
1075            # already filled
1076
1077    def handling_async_forcing(self):
1078        self.resume_after_guard_not_forced = 1
1079
1080    def consume_one_section(self, blackholeinterp):
1081        self.blackholeinterp = blackholeinterp
1082        info = blackholeinterp.get_current_position_info()
1083        self._prepare_next_section(info)
1084
1085    def consume_virtualref_info(self, vrefinfo, numb, end):
1086        # we have to decode a list of references containing pairs
1087        # [..., virtual, vref, ...]  stopping at 'end'
1088        assert (end & 1) == 0
1089        for i in range(0, end, 2):
1090            virtual = self.decode_ref(numb.nums[i])
1091            vref = self.decode_ref(numb.nums[i+1])
1092            # For each pair, we store the virtual inside the vref.
1093            vrefinfo.continue_tracing(vref, virtual)
1094
1095    def consume_vable_info(self, vinfo, numb):
1096        # we have to ignore the initial part of 'nums' (containing vrefs),
1097        # find the virtualizable from nums[-1], load all other values
1098        # from the CPU stack, and copy them into the virtualizable
1099        if vinfo is None:
1100            return len(numb.nums)
1101        index = len(numb.nums) - 1
1102        virtualizable = self.decode_ref(numb.nums[index])
1103        if self.resume_after_guard_not_forced == 1:
1104            # in the middle of handle_async_forcing()
1105            assert vinfo.gettoken(virtualizable)
1106            vinfo.settoken(virtualizable, vinfo.TOKEN_NONE)
1107        else:
1108            # just jumped away from assembler (case 4 in the comment in
1109            # virtualizable.py) into tracing (case 2); check that vable_token
1110            # is and stays 0.  Note the call to reset_vable_token() in
1111            # warmstate.py.
1112            assert not vinfo.gettoken(virtualizable)
1113        return vinfo.write_from_resume_data_partial(virtualizable, self, numb)
1114
1115    def load_value_of_type(self, TYPE, tagged):
1116        from pypy.jit.metainterp.warmstate import specialize_value
1117        kind = getkind(TYPE)
1118        if kind == 'int':
1119            x = self.decode_int(tagged)
1120        elif kind == 'ref':
1121            x = self.decode_ref(tagged)
1122        elif kind == 'float':
1123            x = self.decode_float(tagged)
1124        else:
1125            raise AssertionError(kind)
1126        return specialize_value(TYPE, x)
1127    load_value_of_type._annspecialcase_ = 'specialize:arg(1)'
1128
1129    def consume_vref_and_vable(self, vrefinfo, vinfo, ginfo):
1130        numb = self.cur_numb
1131        self.cur_numb = numb.prev
1132        if self.resume_after_guard_not_forced != 2:
1133            end_vref = self.consume_vable_info(vinfo, numb)
1134            if ginfo is not None: end_vref -= 1
1135            self.consume_virtualref_info(vrefinfo, numb, end_vref)
1136
1137    def allocate_with_vtable(self, known_class):
1138        from pypy.jit.metainterp.executor import exec_new_with_vtable
1139        return exec_new_with_vtable(self.cpu, known_class)
1140
1141    def allocate_struct(self, typedescr):
1142        return self.cpu.bh_new(typedescr)
1143
1144    def allocate_array(self, arraydescr, length):
1145        return self.cpu.bh_new_array(arraydescr, length)
1146
1147    def allocate_string(self, length):
1148        return self.cpu.bh_newstr(length)
1149
1150    def string_setitem(self, str, index, charnum):
1151        char = self.decode_int(charnum)
1152        self.cpu.bh_strsetitem(str, index, char)
1153
1154    def concat_strings(self, str1num, str2num):
1155        str1 = self.decode_ref(str1num)
1156        str2 = self.decode_ref(str2num)
1157        str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str1)
1158        str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str2)
1159        cic = self.callinfocollection
1160        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
1161        result = funcptr(str1, str2)
1162        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
1163
1164    def slice_string(self, strnum, startnum, lengthnum):
1165        str = self.decode_ref(strnum)
1166        start = self.decode_int(startnum)
1167        length = self.decode_int(lengthnum)
1168        str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str)
1169        cic = self.callinfocollection
1170        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
1171        result = funcptr(str, start, start + length)
1172        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
1173
1174    def allocate_unicode(self, length):
1175        return self.cpu.bh_newunicode(length)
1176
1177    def unicode_setitem(self, str, index, charnum):
1178        char = self.decode_int(charnum)
1179        self.cpu.bh_unicodesetitem(str, index, char)
1180
1181    def concat_unicodes(self, str1num, str2num):
1182        str1 = self.decode_ref(str1num)
1183        str2 = self.decode_ref(str2num)
1184        str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str1)
1185        str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str2)
1186        cic = self.callinfocollection
1187        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
1188        result = funcptr(str1, str2)
1189        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
1190
1191    def slice_unicode(self, strnum, startnum, lengthnum):
1192        str = self.decode_ref(strnum)
1193        start = self.decode_int(startnum)
1194        length = self.decode_int(lengthnum)
1195        str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str)
1196        cic = self.callinfocollection
1197        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
1198        result = funcptr(str, start, start + length)
1199        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
1200
1201    def setfield(self, descr, struct, fieldnum):
1202        if descr.is_pointer_field():
1203            newvalue = self.decode_ref(fieldnum)
1204            self.cpu.bh_setfield_gc_r(struct, descr, newvalue)
1205        elif descr.is_float_field():
1206            newvalue = self.decode_float(fieldnum)
1207            self.cpu.bh_setfield_gc_f(struct, descr, newvalue)
1208        else:
1209            newvalue = self.decode_int(fieldnum)
1210            self.cpu.bh_setfield_gc_i(struct, descr, newvalue)
1211
1212    def setinteriorfield(self, index, descr, array, fieldnum):
1213        if descr.is_pointer_field():
1214            newvalue = self.decode_ref(fieldnum)
1215            self.cpu.bh_setinteriorfield_gc_r(array, index, descr, newvalue)
1216        elif descr.is_float_field():
1217            newvalue = self.decode_float(fieldnum)
1218            self.cpu.bh_setinteriorfield_gc_f(array, index, descr, newvalue)
1219        else:
1220            newvalue = self.decode_int(fieldnum)
1221            self.cpu.bh_setinteriorfield_gc_i(array, index, descr, newvalue)
1222
1223    def setarrayitem_int(self, arraydescr, array, index, fieldnum):
1224        newvalue = self.decode_int(fieldnum)
1225        self.cpu.bh_setarrayitem_gc_i(arraydescr, array, index, newvalue)
1226
1227    def setarrayitem_ref(self, arraydescr, array, index, fieldnum):
1228        newvalue = self.decode_ref(fieldnum)
1229        self.cpu.bh_setarrayitem_gc_r(arraydescr, array, index, newvalue)
1230
1231    def setarrayitem_float(self, arraydescr, array, index, fieldnum):
1232        newvalue = self.decode_float(fieldnum)
1233        self.cpu.bh_setarrayitem_gc_f(arraydescr, array, index, newvalue)
1234
1235    def decode_int(self, tagged):
1236        num, tag = untag(tagged)
1237        if tag == TAGCONST:
1238            return self.consts[num].getint()
1239        elif tag == TAGINT:
1240            return num
1241        else:
1242            assert tag == TAGBOX
1243            if num < 0:
1244                num += self.cpu.get_latest_value_count()
1245            return self.cpu.get_latest_value_int(num)
1246
1247    def decode_ref(self, tagged):
1248        num, tag = untag(tagged)
1249        if tag == TAGCONST:
1250            if tagged_eq(tagged, NULLREF):
1251                return self.cpu.ts.NULLREF
1252            return self.consts[num].getref_base()
1253        elif tag == TAGVIRTUAL:
1254            return self.getvirtual(num)
1255        else:
1256            assert tag == TAGBOX
1257            if num < 0:
1258                num += self.cpu.get_latest_value_count()
1259            return self.cpu.get_latest_value_ref(num)
1260
1261    def decode_float(self, tagged):
1262        num, tag = untag(tagged)
1263        if tag == TAGCONST:
1264            return self.consts[num].getfloatstorage()
1265        else:
1266            assert tag == TAGBOX
1267            if num < 0:
1268                num += self.cpu.get_latest_value_count()
1269            return self.cpu.get_latest_value_float(num)
1270
1271    def write_an_int(self, index, int):
1272        self.blackholeinterp.setarg_i(index, int)
1273
1274    def write_a_ref(self, index, ref):
1275        self.blackholeinterp.setarg_r(index, ref)
1276
1277    def write_a_float(self, index, float):
1278        self.blackholeinterp.setarg_f(index, float)
1279
1280# ____________________________________________________________
1281
1282def dump_storage(storage, liveboxes):
1283    "For profiling only."
1284    from pypy.rlib.objectmodel import compute_unique_id
1285    debug_start("jit-resume")
1286    if have_debug_prints():
1287        debug_print('Log storage', compute_uni

Large files files are truncated, but you can click here to view the full file