1. Taavi Burns
  2. pypy


Maciej Fijalkowski  committed ded3dd3

(fijal, arigo) reintroduce oopspecs and optimize newlist_hint correctly
in the JIT

  • Participants
  • Parent commits 16cac49
  • Branches speedup-list-comprehension

Comments (0)

Files changed (11)

File pypy/interpreter/baseobjspace.py

View file
  • Ignore whitespace
 from pypy.interpreter.miscutils import ThreadLocals
 from pypy.tool.cache import Cache
 from pypy.tool.uid import HUGEVAL_BYTES
-from pypy.rlib.objectmodel import we_are_translated, newlist, compute_unique_id
+from pypy.rlib.objectmodel import we_are_translated, newlist_hint,\
+     compute_unique_id
 from pypy.rlib.debug import make_sure_not_resized
 from pypy.rlib.timer import DummyTimer, Timer
 from pypy.rlib.rarithmetic import r_uint
             items = []
-                items = newlist(lgt_estimate)
+                items = newlist_hint(lgt_estimate)
             except MemoryError:
                 items = [] # it might have lied

File pypy/interpreter/pyopcode.py

View file
  • Ignore whitespace
 from pypy.interpreter import gateway, function, eval, pyframe, pytraceback
 from pypy.interpreter.pycode import PyCode
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.objectmodel import we_are_translated, newlist
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import jit, rstackovf
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.debug import check_nonneg
-from pypy.tool.stdlib_opcode import (bytecode_spec, host_bytecode_spec,
-                                     unrolling_all_opcode_descs, opmap,
-                                     host_opmap)
+from pypy.tool.stdlib_opcode import (bytecode_spec,
+                                     unrolling_all_opcode_descs)
 def unaryoperation(operationname):

File pypy/jit/codewriter/jtransform.py

View file
  • Ignore whitespace
     def handle_builtin_call(self, op):
         oopspec_name, args = support.decode_builtin_call(op)
         # dispatch to various implementations depending on the oopspec_name
-        if oopspec_name.startswith('list.') or oopspec_name == 'newlist':
+        if oopspec_name.startswith('list.') or oopspec_name.startswith('newlist'):
             prepare = self._handle_list_call
         elif oopspec_name.startswith('stroruni.'):
             prepare = self._handle_stroruni_call
                                arraydescr, v_length],
+    def do_resizable_newlist_hint(self, op, args, arraydescr, lengthdescr,
+                                  itemsdescr, structdescr):
+        v_hint = self._get_initial_newlist_length(op, args)
+        return SpaceOperation('newlist_hint',
+                              [structdescr, lengthdescr, itemsdescr,
+                               arraydescr, v_hint],
+                              op.result)
     def do_resizable_list_getitem(self, op, args, arraydescr, lengthdescr,
                                   itemsdescr, structdescr):
         v_index, extraop = self._prepare_list_getset(op, lengthdescr, args,

File pypy/jit/codewriter/support.py

View file
  • Ignore whitespace
 _ll_1_newlist.need_result_type = True
 _ll_2_newlist.need_result_type = True
+def _ll_1_newlist_hint(LIST, hint):
+    return LIST.ll_newlist_hint(hint)
+_ll_1_newlist_hint.need_result_type = True
 def _ll_1_list_len(l):
     return l.ll_length()
 def _ll_2_list_getitem(l, index):

File pypy/jit/metainterp/blackhole.py

View file
  • Ignore whitespace
         cpu.bh_setfield_gc_r(result, itemsdescr, items)
         return result
+    @arguments("cpu", "d", "d", "d", "d", "i", returns="r")
+    def bhimpl_newlist_hint(cpu, structdescr, lengthdescr, itemsdescr,
+                            arraydescr, lengthhint):
+        result = cpu.bh_new(structdescr)
+        cpu.bh_setfield_gc_i(result, lengthdescr, 0)
+        items = cpu.bh_new_array(arraydescr, lengthhint)
+        cpu.bh_setfield_gc_r(result, itemsdescr, items)
+        return result
     @arguments("cpu", "r", "d", "d", "i", returns="i")
     def bhimpl_getlistitem_gc_i(cpu, lst, itemsdescr, arraydescr, index):
         items = cpu.bh_getfield_gc_r(lst, itemsdescr)

File pypy/jit/metainterp/pyjitpl.py

View file
  • Ignore whitespace
         self._opimpl_setfield_gc_any(sbox, itemsdescr, abox)
         return sbox
+    @arguments("descr", "descr", "descr", "descr", "box")
+    def opimpl_newlist_hint(self, structdescr, lengthdescr, itemsdescr,
+                            arraydescr, sizehintbox):
+        sbox = self.opimpl_new(structdescr)
+        self._opimpl_setfield_gc_any(sbox, lengthdescr, history.CONST_FALSE)
+        abox = self.opimpl_new_array(arraydescr, sizehintbox)
+        self._opimpl_setfield_gc_any(sbox, itemsdescr, abox)
+        return sbox
     @arguments("box", "descr", "descr", "box")
     def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr,

File pypy/jit/metainterp/test/test_list.py

View file
  • Ignore whitespace
 import py
+from pypy.rlib.objectmodel import newlist_hint
 from pypy.rlib.jit import JitDriver
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
         self.check_resops({'jump': 1, 'int_gt': 2, 'int_add': 2,
                            'guard_true': 2, 'int_sub': 2})
+    def test_newlist_hint(self):
+        def f(i):
+            l = newlist_hint(i)
+            return len(l)
+        r = self.interp_operations(f, [3])
+        assert r == 0
+    def test_newlist_hint_optimized(self):
+        driver = JitDriver(greens = [], reds = ['i'])
+        def f(i):
+            while i > 0:
+                driver.jit_merge_point(i=i)
+                l = newlist_hint(5)
+                l.append(1)
+                i -= l[0]
+        self.meta_interp(f, [10], listops=True)
+        self.check_resops(new_array=0, call=0)
 class TestOOtype(ListTests, OOJitMixin):

File pypy/objspace/std/listobject.py

View file
  • Ignore whitespace
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
 from pypy.objspace.std import slicetype
 from pypy.interpreter import gateway, baseobjspace
-from pypy.rlib.objectmodel import instantiate, specialize, newlist
+from pypy.rlib.objectmodel import instantiate, specialize, newlist_hint
 from pypy.rlib.listsort import make_timsort_class
 from pypy.rlib import rerased, jit, debug
 from pypy.interpreter.argument import Signature
     def get_empty_storage(self, sizehint):
         if sizehint == -1:
             return self.erase([])
-        return self.erase(newlist(sizehint))
+        return self.erase(newlist_hint(sizehint))
     def clone(self, w_list):
         l = self.unerase(w_list.lstorage)

File pypy/rlib/objectmodel.py

View file
  • Ignore whitespace
 # ____________________________________________________________
-def newlist(sizehint=0):
+def newlist_hint(sizehint=0):
     """ Create a new list, but pass a hint how big the size should be
     return []
 class Entry(ExtRegistryEntry):
-    _about_ = newlist
+    _about_ = newlist_hint
     def compute_result_annotation(self, s_sizehint):
         from pypy.annotation.model import SomeInteger
         assert isinstance(s_sizehint, SomeInteger)
-        return self.bookkeeper.newlist()
+        s_l = self.bookkeeper.newlist()
+        s_l.listdef.listitem.resize()
+        return s_l
     def specialize_call(self, orig_hop, i_sizehint=None):
         from pypy.rpython.rlist import rtype_newlist

File pypy/rpython/lltypesystem/rlist.py

View file
  • Ignore whitespace
         ITEMARRAY = GcArray(ITEM,
                             adtmeths = ADTIFixedList({
                                  "ll_newlist": ll_fixed_newlist,
-                                 "ll_newlist_hint": ll_fixed_newlist,
                                  "ll_newemptylist": ll_fixed_newemptylist,
                                  "ll_length": ll_fixed_length,
                                  "ll_items": ll_fixed_items,
     l.items = malloc(LIST.items.TO, length)
     return l
 ll_newlist = typeMethod(ll_newlist)
+ll_newlist.oopspec = 'newlist(length)'
 def ll_newlist_hint(LIST, lengthhint):
     ll_assert(lengthhint >= 0, "negative list length")
     l.items = malloc(LIST.items.TO, lengthhint)
     return l
 ll_newlist_hint = typeMethod(ll_newlist_hint)
+ll_newlist_hint.oopspec = 'newlist_hint(lengthhint)'
 # should empty lists start with no allocated memory, or with a preallocated
 # minimal number of entries?  XXX compare memory usage versus speed, and
     l.items = _ll_new_empty_item_array(LIST)
     return l
 ll_newemptylist = typeMethod(ll_newemptylist)
+ll_newemptylist.oopspec = 'newlist(0)'
 def ll_length(l):
     return l.length
+ll_length.oopspec = 'list.len(l)'
 def ll_items(l):
     return l.items
 def ll_getitem_fast(l, index):
     ll_assert(index < l.length, "getitem out of bounds")
     return l.ll_items()[index]
+ll_getitem_fast.oopspec = 'list.getitem(l, index)'
 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)'
 # fixed size versions
     ll_assert(length >= 0, "negative fixed list length")
     l = malloc(LIST, length)
     return l
+ll_fixed_newlist = typeMethod(ll_fixed_newlist)
+ll_fixed_newlist.oopspec = 'newlist(length)'
 def ll_fixed_newemptylist(LIST):
     return ll_fixed_newlist(LIST, 0)
+ll_fixed_newemptylist = typeMethod(ll_fixed_newemptylist)
 def ll_fixed_length(l):
     return len(l)
+ll_fixed_length.oopspec = 'list.len(l)'
 ll_fixed_length._always_inline_ = True
 def ll_fixed_items(l):
 def ll_fixed_getitem_fast(l, index):
     ll_assert(index < len(l), "fixed getitem out of bounds")
     return l[index]
-ll_fixed_getitem_fast._always_inline_ = True
+ll_fixed_getitem_fast.oopspec = 'list.getitem(l, index)'
 def ll_fixed_setitem_fast(l, index, item):
     ll_assert(index < len(l), "fixed setitem out of bounds")
     l[index] = item
-ll_fixed_setitem_fast._always_inline_ = True
+ll_fixed_setitem_fast.oopspec = 'list.setitem(l, index, item)'
 def newlist(llops, r_list, items_v, v_sizehint=None):
     LIST = r_list.LIST

File pypy/rpython/test/test_rlist.py

View file
  • Ignore whitespace
                    ("y[*]" in immutable_fields)
     def test_hints(self):
-        from pypy.rlib.objectmodel import newlist
-        from pypy.rpython.annlowlevel import hlstr
+        from pypy.rlib.objectmodel import newlist_hint
         strings = ['abc', 'def']
         def f(i):
             z = strings[i]
-            x = newlist(sizehint=13)
+            x = newlist_hint(sizehint=13)
             x += z
             return ''.join(x)