[pypy-dev] Disassembling methods called by LOOKUP_METHOD

Ryan Gonzalez rymg19 at gmail.com
Fri Mar 3 09:58:58 EST 2017


You can look at the source code for the objects (all located in
pypy/objspace/std) and find the method implementations there.

Here's append's (form pypy/objspace/std/listobject.py):


    def append(self, w_item):
        """L.append(object) -- append object to end"""
        self.strategy.append(self, w_item)


So it's just appending to an RPython list. If you want to see the source
for that, look in rpython/rtyper. append's is in rpython/rtyper/rlist.py:


    def rtype_method_append(self, hop):
        v_lst, v_value = hop.inputargs(self, self.item_repr)
        hop.exception_cannot_occur()
        hop.gendirectcall(ll_append, v_lst, v_value)


This ends up calling ll_append in the end (I think the other stuff is for
the JIT?), which is defined in the same file:


def ll_append(l, newitem):
    length = l.ll_length()
    l._ll_resize_ge(length+1)           # see "a note about overflows" above
    l.ll_setitem_fast(length, newitem)


Now, these ll_* functions are defined in the corresponding file inside
rpython/rtyper/lltypesystem; in this case, it's
rpython/rtyper/lltypesystem/rlist.py:


            self.LIST.become(GcStruct("list", ("length", Signed),
                                              ("items", Ptr(ITEMARRAY)),
                                      adtmeths = ADTIList({
                                          "ll_newlist": ll_newlist,
                                          "ll_newlist_hint":
ll_newlist_hint,
                                          "ll_newemptylist":
ll_newemptylist,
                                          "ll_length": ll_length,
                                          "ll_items": ll_items,
                                          "ITEM": ITEM,
                                          "ll_getitem_fast":
ll_getitem_fast,
                                          "ll_setitem_fast":
ll_setitem_fast,
                                          "_ll_resize_ge":
_ll_list_resize_ge,
                                          "_ll_resize_le":
_ll_list_resize_le,
                                          "_ll_resize": _ll_list_resize,
                                          "_ll_resize_hint":
_ll_list_resize_hint,
                                      }),
                                      hints = {'list': True})
                             )


It's signaling to RPython all the different methods on the low-level list
representation. Here, you want ll_setitem_fast and _ll_list_resize_ge (I
also copy-pasted the functions they call):


@jit.look_inside_iff(lambda l, newsize, overallocate:
jit.isconstant(len(l.items)) and jit.isconstant(newsize))
@signature(types.any(), types.int(), types.bool(), returns=types.none())
def _ll_list_resize_hint_really(l, newsize, overallocate):
    """
    Ensure l.items has room for at least newsize elements.  Note that
    l.items may change, and even if newsize is less than l.length on
    entry.
    """
    # This over-allocates proportional to the list size, making room
    # for additional growth.  The over-allocation is mild, but is
    # enough to give linear-time amortized behavior over a long
    # sequence of appends() in the presence of a poorly-performing
    # system malloc().
    # The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
    if newsize <= 0:
        ll_assert(newsize == 0, "negative list length")
        l.length = 0
        l.items = _ll_new_empty_item_array(typeOf(l).TO)
        return
    elif overallocate:
        if newsize < 9:
            some = 3
        else:
            some = 6
        some += newsize >> 3
        new_allocated = newsize + some
    else:
        new_allocated = newsize
    # new_allocated is a bit more than newsize, enough to ensure an
amortized
    # linear complexity for e.g. repeated usage of l.append().  In case
    # it overflows sys.maxint, it is guaranteed negative, and the following
    # malloc() will fail.
    items = l.items
    newitems = malloc(typeOf(l).TO.items.TO, new_allocated)
    before_len = l.length
    if before_len:   # avoids copying GC flags from the prebuilt_empty_array
        if before_len < newsize:
            p = before_len
        else:
            p = newsize
        rgc.ll_arraycopy(items, newitems, 0, 0, p)
    l.items = newitems


def _ll_list_resize_ge(l, newsize):
    """This is called with 'newsize' larger than the current length of the
    list.  If the list storage doesn't have enough space, then really
perform
    a realloc().  In the common case where we already overallocated enough,
    then this is a very fast operation.
    """
    cond = len(l.items) < newsize
    if jit.isconstant(len(l.items)) and jit.isconstant(newsize):
        if cond:
            _ll_list_resize_hint_really(l, newsize, True)
    else:
        jit.conditional_call(cond,
                             _ll_list_resize_hint_really, l, newsize, True)
    l.length = newsize


def ll_items(l):
    return l.items


def ll_setitem_fast(l, index, item):
    ll_assert(index < l.length, "setitem out of bounds")
    l.ll_items()[index] = item
ll_setitem_fast.oopspec = 'list.setitem(l, index, item)'


On Fri, Mar 3, 2017 at 8:20 AM, Frank Wang <frankw at mit.edu> wrote:

> Hi,
>
> I'm trying to figure out the opcodes that the "append" function calls for
> arrays. When I use the dis tool, it just says that it looks up a method
> "append" using the LOOKUP_METHOD opcode. Is there a tool that allows me to
> disassemble built-in functions like "append", or what the best way to do
> this is?
>
> Thanks,
> Frank
>
> _______________________________________________
> pypy-dev mailing list
> pypy-dev at python.org
> https://mail.python.org/mailman/listinfo/pypy-dev
>
>


-- 
Ryan (ライアン)
Yoko Shimomura > ryo (supercell/EGOIST) > Hiroyuki Sawano >> everyone else
http://refi64.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pypy-dev/attachments/20170303/3e9fa620/attachment-0001.html>


More information about the pypy-dev mailing list