Author: Armin Rigo <[email protected]>
Branch: op_malloc_gc
Changeset: r50619:dc4fca252174
Date: 2011-12-17 15:28 +0100
http://bitbucket.org/pypy/pypy/changeset/dc4fca252174/
Log: In-progress: found a hopefully reasonable solution, namely a
CALL_MALLOC_GC operation that is basically just a CALL, invoking
whatever helper rewrite.py wants to introduce.
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -42,6 +42,15 @@
self.field_unicodelen_descr = get_field_arraylen_descr(self,
rstr.UNICODE)
+ def _ready(self):
+ MALLOC_FIXEDSIZE = lltype.Ptr(
+ lltype.FuncType([lltype.Signed], llmemory.GCREF))
+ self.malloc_fixedsize_fn = llhelper(MALLOC_FIXEDSIZE,
+ self.malloc_fixedsize)
+ self.c_malloc_fixedsize_fn = ConstInt(
+ heaptracker.adr2int(llmemory.cast_ptr_to_adr(
+ self.malloc_fixedsize_fn)))
+
def _freeze_(self):
return True
def initialize(self):
@@ -55,28 +64,11 @@
def freeing_block(self, start, stop):
pass
- def get_funcptr_for_malloc_gc_fixed(self):
- """Returns a function pointer to a function that implements
- the simple case of MALLOC_GC: the case where the variable size
- is zero. The function pointer has signature (size) -> GCREF."""
- raise NotImplementedError
-
- def get_funcptr_for_malloc_gc_variable(self):
- """Returns a function pointer to a function that implements
- the complex case of MALLOC_GC: the case where the variable size
- is not known to be zero. The signature is:
- (base_size, num_elem, item_size) -> GCREF"""
- raise NotImplementedError
-
def gc_malloc(self, sizedescr):
"""Blackhole: do a 'bh_new'. Also used for 'bh_new_with_vtable',
with the vtable pointer set manually afterwards."""
assert isinstance(sizedescr, BaseSizeDescr)
- mallocptr = self.get_funcptr_for_malloc_gc_fixed()
- res = mallocptr(sizedescr.size)
- if res:
- self._set_tid(res, sizedescr.tid)
- return res
+ return self._gc_malloc(sizedescr.size, sizedescr.tid)
def gc_malloc_array(self, arraydescr, num_elem):
assert isinstance(arraydescr, BaseArrayDescr)
@@ -98,18 +90,6 @@
self.unicode_ofs_length,
self.unicode_type_id)
- def _gc_malloc_array(self, basesize, num_elem, itemsize, ofs_length, tid):
- mallocptr = self.get_funcptr_for_malloc_gc_variable()
- res = mallocptr(basesize, num_elem, itemsize)
- if res:
- self._set_tid(res, tid)
- arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
- arrayptr[ofs_length/WORD] = num_elem
- return res
-
- def _set_tid(self, gcptr, tid):
- pass # unless overridden
-
def _record_constptrs(self, op, gcrefs_output_list):
for i in range(op.numargs()):
v = op.getarg(i)
@@ -180,24 +160,35 @@
def __init__(self, gcdescr, translator, rtyper):
GcLLDescription.__init__(self, gcdescr, translator, rtyper)
# grab a pointer to the Boehm 'malloc' function
- self.malloc_fn_ptr = self.configure_boehm_once()
+ malloc_fn_ptr = self.configure_boehm_once()
+ self.malloc_fn_ptr = malloc_fn_ptr
#
- def malloc_gc_variable(basesize, num_elem, itemsize):
- try:
- size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
- except OverflowError:
- return lltype.nullptr(llmemory.GCREF.TO)
- return self.malloc_fn_ptr(size)
+ def malloc_fixedsize(size):
+ res = malloc_fn_ptr(size)
+ if not res:
+ raise MemoryError
+ return res
+ self.malloc_fixedsize = malloc_fixedsize
#
- self.malloc_gc_variable = malloc_gc_variable
- self.MALLOC_GC_VARIABLE = lltype.Ptr(
- lltype.FuncType([lltype.Signed] * 3, llmemory.GCREF))
+ self._ready()
- def get_funcptr_for_malloc_gc_fixed(self):
- return self.malloc_fn_ptr
+ def _gc_malloc(self, size, tid):
+ # Boehm: 'tid' is ignored
+ return self.malloc_fixedsize(size)
- def get_funcptr_for_malloc_gc_variable(self):
- return llhelper(self.MALLOC_GC_VARIABLE, self.malloc_gc_variable)
+ def _gc_malloc_array(self, basesize, num_elem, itemsize, ofs_length, tid):
+ # Boehm: 'tid' is ignored
+ try:
+ totalsize = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+ except OverflowError:
+ raise MemoryError
+ res = self.malloc_fn_ptr(totalsize)
+ if not res:
+ raise MemoryError
+ arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
+ arrayptr[ofs_length/WORD] = num_elem
+ return res
+
# ____________________________________________________________
# All code below is for the hybrid or minimark GC
diff --git a/pypy/jit/backend/llsupport/rewrite.py
b/pypy/jit/backend/llsupport/rewrite.py
--- a/pypy/jit/backend/llsupport/rewrite.py
+++ b/pypy/jit/backend/llsupport/rewrite.py
@@ -11,8 +11,11 @@
#
# - Remove the DEBUG_MERGE_POINTs.
#
- # - Turn all NEW_xxx to MALLOC_GC operations, possibly followed by
- # SETFIELDs in order to initialize their GC fields.
+ # - Turn all NEW_xxx to either a CALL_MALLOC_GC, or a CALL_MALLOC_NURSERY
+ # followed by SETFIELDs in order to initialize their GC fields. The
+ # two advantages of CALL_MALLOC_NURSERY is that it inlines the common
+ # path, and we need only one such operation to allocate several blocks
+ # of memory at once.
#
# - Add COND_CALLs to the write barrier before SETFIELD_GC and
# SETARRAYITEM_GC operations.
@@ -40,7 +43,7 @@
for op in operations:
if op.getopnum() == rop.DEBUG_MERGE_POINT:
continue
- # ---------- fold the NEWxxx operations into MALLOC_GC ----------
+ # ---------- turn NEWxxx into CALL_MALLOC_xxx ----------
if op.is_malloc():
self.handle_malloc_operation(op)
continue
@@ -116,11 +119,12 @@
var_size = ovfcheck(item_size * num_elem)
total_size = ovfcheck(base_size + var_size)
except OverflowError:
- pass
+ pass # total_size is still -1
if total_size >= 0:
self.gen_malloc_nursery(total_size, op.result)
else:
- self.gen_malloc_gc(base_size, op.result,
+ xxx
+ self.gen_new_array(base_size, op.result,
v_length, ConstInt(item_size))
self.gen_initialize_tid(op.result, tid)
self.gen_initialize_len(op.result, v_length, arraylen_descr)
@@ -135,12 +139,14 @@
self._op_malloc_nursery = None
self.recent_mallocs.clear()
- def gen_malloc_gc(self, size, v_result,
- v_num_elem=c_zero, c_item_size=c_zero):
- """Generate a MALLOC_GC."""
+ def gen_malloc_fixedsize(self, size, v_result):
+ """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, Const(size)).
+ Note that with the framework GC, this should be called very rarely.
+ """
+ self.emitting_an_operation_that_can_collect()
c_size = ConstInt(size)
- self.emitting_an_operation_that_can_collect()
- op = ResOperation(rop.MALLOC_GC, [c_size, v_num_elem, c_item_size],
+ op = ResOperation(rop.CALL_MALLOC_GC,
+ [self.gc_ll_descr.c_malloc_fixedsize_fn, c_size],
v_result)
self.newops.append(op)
# mark 'v_result' as freshly malloced
@@ -151,8 +157,7 @@
If that fails, generate a plain MALLOC_GC instead.
"""
if not self.gc_ll_descr.can_use_nursery_malloc(size):
- self.gen_malloc_gc(size, v_result)
- return
+ return self.gen_malloc_fixedsize(size, v_result)
#
size = self.round_up_for_allocation(size)
op = None
@@ -178,6 +183,7 @@
self._previous_size = size
self._v_last_malloced_nursery = v_result
self.recent_mallocs[v_result] = None
+ return True
def gen_initialize_tid(self, v_newgcobj, tid):
if self.gc_ll_descr.fielddescr_tid is not None:
diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py
b/pypy/jit/backend/llsupport/test/test_rewrite.py
--- a/pypy/jit/backend/llsupport/test/test_rewrite.py
+++ b/pypy/jit/backend/llsupport/test/test_rewrite.py
@@ -15,6 +15,8 @@
class RewriteTests(object):
def check_rewrite(self, frm_operations, to_operations):
+ malloc_fixedsize = self.gc_ll_descr.malloc_fixedsize_fn
+ #
S = lltype.GcStruct('S', ('x', lltype.Signed),
('y', lltype.Signed))
sdescr = get_size_descr(self.gc_ll_descr, S)
@@ -84,7 +86,7 @@
jump()
""", """
[p1]
- p0 = malloc_gc(%(sdescr.size)d, 0, 0)
+ p0 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d)
jump()
""")
@@ -96,8 +98,8 @@
jump()
""", """
[]
- p0 = malloc_gc(%(sdescr.size)d, 0, 0)
- p1 = malloc_gc(%(sdescr.size)d, 0, 0)
+ p0 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d)
+ p1 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d)
jump()
""")
@@ -108,8 +110,9 @@
jump()
""", """
[]
- p0 = malloc_gc(%(adescr.get_base_size(False) + \
- 10 * adescr.get_item_size(False))d, 0, 0)
+ p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \
+ %(adescr.get_base_size(False) + \
+ 10 * adescr.get_item_size(False))d)
setfield_gc(p0, 10, descr=alendescr)
jump()
""")
@@ -121,8 +124,10 @@
jump()
""", """
[i1]
- p0 = malloc_gc(%(adescr.get_base_size(False))d, \
- i1, %(adescr.get_item_size(False))d)
+ p0 = call_malloc_gc(ConstClass(malloc_varsize), \
+ %(adescr.get_base_size(False))d, \
+ i1, \
+ %(adescr.get_item_size(False))d)
setfield_gc(p0, i1, descr=alendescr)
jump()
""")
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -344,8 +344,8 @@
rop.SETINTERIORFIELD_RAW,
rop.CALL_RELEASE_GIL,
rop.QUASIIMMUT_FIELD,
- rop.MALLOC_GC,
- rop.MALLOC_NURSERY,
+ rop.CALL_MALLOC_GC,
+ rop.CALL_MALLOC_NURSERY,
rop.LABEL,
): # list of opcodes never executed by pyjitpl
continue
diff --git a/pypy/jit/metainterp/resoperation.py
b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -472,8 +472,6 @@
'NEW_ARRAY/1d',
'NEWSTR/1',
'NEWUNICODE/1',
- 'MALLOC_GC/3', # added by llsupport/gc: malloc of C1+N*C2 bytes
- 'MALLOC_NURSERY/1', # added by llsupport/gc: nursery malloc, const bytes
'_MALLOC_LAST',
'FORCE_TOKEN/0',
'VIRTUAL_REF/2', # removed before it's passed to the backend
@@ -510,6 +508,8 @@
#'OOSEND', # ootype operation
#'OOSEND_PURE', # ootype operation
'CALL_PURE/*d', # removed before it's passed to the backend
+ 'CALL_MALLOC_GC/*d', # like CALL, but NULL => propagate MemoryError
+ 'CALL_MALLOC_NURSERY/2d', # nursery malloc, const number of bytes, zeroed
'_CALL_LAST',
'_CANRAISE_LAST', # ----- end of can_raise operations -----
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit