def graph2delayed(self, graph, FUNCTYPE=None): if FUNCTYPE is None: FUNCTYPE = lltype.ForwardReference() # obscure hack: embed the name of the function in the string, so # that the genc database can get it even before the delayedptr # is really computed name = "delayed!%s" % (graph.name,) delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), name, solid=True) self.delayedfuncs.append((delayedptr, graph)) return delayedptr
def delayedconst(self, repr, obj): if repr.is_setup_delayed(): # record the existence of this 'obj' for the bookkeeper - e.g. # if 'obj' is an instance, this will populate the classdef with # the prebuilt attribute values of the instance bk = self.rtyper.annotator.bookkeeper bk.immutablevalue(obj) delayedptr = lltype._ptr(repr.lowleveltype, "delayed!") self.delayedconsts.append((delayedptr, repr, obj)) return delayedptr else: return repr.convert_const(obj)
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): if T.TO._arrayfld is not None: lgt = getattr(cobj.contents, T.TO._arrayfld).length container = lltype._struct(T.TO, lgt) else: container = lltype._struct(T.TO) struct_use_ctypes_storage(container, cobj.contents) elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: raise NotImplementedError("array with an explicit length") elif isinstance(T.TO, lltype.FuncType): _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): if T.TO._arrayfld is not None: raise NotImplementedError("XXX var-sized structs") container = lltype._struct(T.TO) struct_use_ctypes_storage(container, cobj.contents) elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: raise NotImplementedError("array with an explicit length") elif isinstance(T.TO, lltype.FuncType): _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def guess_size_obj(obj): TYPE = typeOf(obj) ptr = _ptr(Ptr(TYPE), obj) if TYPE._is_varsize(): arrayfld = getattr(TYPE, '_arrayfld', None) if arrayfld: length = len(getattr(ptr, arrayfld)) else: try: length = len(ptr) except TypeError: print "couldn't find size of", ptr return 0 else: length = None return convert_offset_to_int(llmemory.sizeof(TYPE, length))
def graph2delayed(self, graph, FUNCTYPE=None): if self.rtyper.type_system.name == 'lltypesystem': if FUNCTYPE is None: FUNCTYPE = lltype.ForwardReference() # obscure hack: embed the name of the function in the string, so # that the genc database can get it even before the delayedptr # is really computed name = "delayed!%s" % (graph.name, ) delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), name, solid=True) else: if FUNCTYPE is None: FUNCTYPE = ootype.ForwardReference() name = "delayed!%s" % (graph.name, ) delayedptr = ootype._forward_static_meth(FUNCTYPE, _name=name) self.delayedfuncs.append((delayedptr, graph)) return delayedptr
def delayedconst(self, repr, obj): if repr.is_setup_delayed(): # record the existence of this 'obj' for the bookkeeper - e.g. # if 'obj' is an instance, this will populate the classdef with # the prebuilt attribute values of the instance bk = self.rtyper.annotator.bookkeeper bk.immutablevalue(obj) if self.rtyper.type_system.name == 'lltypesystem': delayedptr = lltype._ptr(repr.lowleveltype, "delayed!") else: delayedptr = ootype.make_instance(repr.lowleveltype) self.delayedconsts.append((delayedptr, repr, obj)) return delayedptr else: return repr.convert_const(obj)
def cast_object_to_ptr(PTR, object): """NOT_RPYTHON: hack. The object may be disguised as a PTR now. Limited to casting a given object to a single type. """ if isinstance(PTR, lltype.Ptr): TO = PTR.TO else: TO = PTR if not hasattr(object, '_carry_around_for_tests'): assert not hasattr(object, '_TYPE') object._carry_around_for_tests = True object._TYPE = TO else: assert object._TYPE == TO # if isinstance(PTR, lltype.Ptr): return lltype._ptr(PTR, object, True) elif isinstance(PTR, ootype.Instance): return object else: raise NotImplementedError("cast_object_to_ptr(%r, ...)" % PTR)
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if T is lltype.Void: return None if isinstance(T, lltype.Typedef): T = T.OF if isinstance(T, lltype.Ptr): ptrval = ctypes.cast(cobj, ctypes.c_void_p).value if not cobj or not ptrval: # NULL pointer # CFunctionType.__nonzero__ is broken before Python 2.6 return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): if T.TO._gckind == 'gc' and ptrval & 1: # a tagged pointer gcref = _opaque_objs[ptrval // 2].hide() return lltype.cast_opaque_ptr(T, gcref) REAL_TYPE = T.TO if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) container = lltype._struct(T.TO, carray.length) else: # special treatment of 'OBJECT' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT) >= 0: # figure out the real type of the object containerheader = lltype._struct(OBJECT) cobjheader = ctypes.cast(cobj, get_ctypes_type(lltype.Ptr(OBJECT))) struct_use_ctypes_storage(containerheader, cobjheader) REAL_TYPE = get_rtyper().get_type_for_typeptr( containerheader.typeptr) REAL_T = lltype.Ptr(REAL_TYPE) cobj = ctypes.cast(cobj, get_ctypes_type(REAL_T)) container = lltype._struct(REAL_TYPE) struct_use_ctypes_storage(container, cobj) if REAL_TYPE != T.TO: p = container._as_ptr() container = lltype.cast_pointer(T, p)._as_obj() # special treatment of 'OBJECT_VTABLE' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT_VTABLE) >= 0: # figure out the real object that this vtable points to, # and just return that p = get_rtyper().get_real_typeptr_for_typeptr( container._as_ptr()) container = lltype.cast_pointer(T, p)._as_obj() elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = type(cobj)(cobj.contents) else: container = _array_of_known_length(T.TO) container._storage = type(cobj)(cobj.contents) elif isinstance(T.TO, lltype.FuncType): cobjkey = intmask(ctypes.cast(cobj, ctypes.c_void_p).value) if cobjkey in _int2obj: container = _int2obj[cobjkey] else: _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): if T == llmemory.GCREF: container = _llgcopaque(cobj) else: container = lltype._opaque(T.TO) cbuf = ctypes.cast(cobj, ctypes.c_void_p) add_storage(container, _parentable_mixin, cbuf) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is llmemory.Address: if cobj is None: llobj = llmemory.NULL else: llobj = _lladdress(cobj) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: try: llobj = unichr(cobj) except (ValueError, OverflowError): for tc in 'HIL': if array(tc).itemsize == array('u').itemsize: import struct cobj &= 256 ** struct.calcsize(tc) - 1 llobj = array('u', array(tc, (cobj,)).tostring())[0] break else: raise elif T is lltype.Signed: llobj = cobj elif T is lltype.Bool: assert cobj == True or cobj == False # 0 and 1 work too llobj = bool(cobj) elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) elif T is lltype.LongFloat: if isinstance(cobj, ctypes.c_longdouble): cobj = cobj.value llobj = r_longfloat(cobj) elif T is lltype.Void: llobj = cobj else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if T is lltype.Void: return None if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): REAL_TYPE = T.TO if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) container = lltype._struct(T.TO, carray.length) else: # special treatment of 'OBJECT' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT) >= 0: # figure out the real type of the object containerheader = lltype._struct(OBJECT) cobjheader = ctypes.cast(cobj, get_ctypes_type(lltype.Ptr(OBJECT))) struct_use_ctypes_storage(containerheader, cobjheader.contents) REAL_TYPE = get_rtyper().get_type_for_typeptr( containerheader.typeptr) REAL_T = lltype.Ptr(REAL_TYPE) cobj = ctypes.cast(cobj, get_ctypes_type(REAL_T)) container = lltype._struct(REAL_TYPE) struct_use_ctypes_storage(container, cobj.contents) if REAL_TYPE != T.TO: p = container._as_ptr() container = lltype.cast_pointer(T, p)._as_obj() # special treatment of 'OBJECT_VTABLE' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT_VTABLE) >= 0: # figure out the real object that this vtable points to, # and just return that p = get_rtyper().get_real_typeptr_for_typeptr( container._as_ptr()) container = lltype.cast_pointer(T, p)._as_obj() elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: container = _array_of_known_length(T.TO) container._storage = cobj.contents elif isinstance(T.TO, lltype.FuncType): cobjkey = ctypes.cast(cobj, ctypes.c_void_p).value if cobjkey in _callback2obj: container = _callback2obj[cobjkey] else: _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): if T == llmemory.GCREF: container = _llgcopaque(cobj) else: container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is llmemory.Address: if cobj is None: llobj = llmemory.NULL else: llobj = _lladdress(cobj) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.Bool: assert cobj == True or cobj == False # 0 and 1 work too llobj = bool(cobj) elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) elif T is lltype.Void: llobj = cobj else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def __init__(self, translator): from pypy.rpython.memory.gc.base import choose_gc_from_config super(FrameworkGCTransformer, self).__init__(translator, inline=True) if hasattr(self, 'GC_PARAMS'): # for tests: the GC choice can be specified as class attributes from pypy.rpython.memory.gc.marksweep import MarkSweepGC GCClass = getattr(self, 'GCClass', MarkSweepGC) GC_PARAMS = self.GC_PARAMS else: # for regular translation: pick the GC from the config GCClass, GC_PARAMS = choose_gc_from_config(translator.config) self.layoutbuilder = TransformerLayoutBuilder(self) self.get_type_id = self.layoutbuilder.get_type_id # set up dummy a table, to be overwritten with the real one in finish() type_info_table = lltype._ptr( lltype.Ptr(gctypelayout.GCData.TYPE_INFO_TABLE), "delayed!type_info_table", solid=True) gcdata = gctypelayout.GCData(type_info_table) # initialize the following two fields with a random non-NULL address, # to make the annotator happy. The fields are patched in finish() # to point to a real array. foo = lltype.malloc(lltype.FixedSizeArray(llmemory.Address, 1), immortal=True, zero=True) a_random_address = llmemory.cast_ptr_to_adr(foo) gcdata.static_root_start = a_random_address # patched in finish() gcdata.static_root_nongcend = a_random_address # patched in finish() gcdata.static_root_end = a_random_address # patched in finish() self.gcdata = gcdata self.malloc_fnptr_cache = {} gcdata.gc = GCClass(**GC_PARAMS) root_walker = self.build_root_walker() gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 self.write_barrier_calls = 0 def frameworkgc_setup(): # run-time initialization code root_walker.setup_root_walker() gcdata.gc.setup() bk = self.translator.annotator.bookkeeper # the point of this little dance is to not annotate # self.gcdata.static_root_xyz as constants. XXX is it still needed?? data_classdef = bk.getuniqueclassdef(gctypelayout.GCData) data_classdef.generalize_attr( 'static_root_start', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_nongcend', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_end', annmodel.SomeAddress()) annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) def getfn(ll_function, args_s, s_result, inline=False, minimal_transform=True): graph = annhelper.getgraph(ll_function, args_s, s_result) if minimal_transform: self.need_minimal_transform(graph) if inline: self.graphs_to_inline[graph] = True return annhelper.graph2const(graph) self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [], annmodel.s_None) if root_walker.need_root_stack: self.incr_stack_ptr = getfn(root_walker.incr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) self.decr_stack_ptr = getfn(root_walker.decr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) else: self.incr_stack_ptr = None self.decr_stack_ptr = None self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) classdef = bk.getuniqueclassdef(GCClass) s_gc = annmodel.SomeInstance(classdef) s_gcref = annmodel.SomePtr(llmemory.GCREF) malloc_fixedsize_clear_meth = GCClass.malloc_fixedsize_clear.im_func self.malloc_fixedsize_clear_ptr = getfn( malloc_fixedsize_clear_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) if hasattr(GCClass, 'malloc_fixedsize'): malloc_fixedsize_meth = GCClass.malloc_fixedsize.im_func self.malloc_fixedsize_ptr = getfn( malloc_fixedsize_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) else: malloc_fixedsize_meth = None self.malloc_fixedsize_ptr = self.malloc_fixedsize_clear_ptr ## self.malloc_varsize_ptr = getfn( ## GCClass.malloc_varsize.im_func, ## [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] ## + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.malloc_varsize_clear_ptr = getfn( GCClass.malloc_varsize_clear.im_func, [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, [s_gc, annmodel.SomeAddress()], annmodel.SomeBool()) # in some GCs we can inline the common case of # malloc_fixedsize(typeid, size, True, False, False) if getattr(GCClass, 'inline_simple_malloc', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside if malloc_fixedsize_meth is None: malloc_fast_meth = malloc_fixedsize_clear_meth self.malloc_fast_is_clearing = True else: malloc_fast_meth = malloc_fixedsize_meth self.malloc_fast_is_clearing = False malloc_fast = func_with_new_name( malloc_fast_meth, "malloc_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_fast_ptr = getfn( malloc_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False, s_False], s_gcref, inline = True) else: self.malloc_fast_ptr = None # in some GCs we can also inline the common case of # malloc_varsize(typeid, length, (3 constant sizes), True, False) if getattr(GCClass, 'inline_simple_malloc_varsize', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside malloc_varsize_clear_fast = func_with_new_name( GCClass.malloc_varsize_clear.im_func, "malloc_varsize_clear_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_varsize_clear_fast_ptr = getfn( malloc_varsize_clear_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False], s_gcref, inline = True) else: self.malloc_varsize_clear_fast_ptr = None if getattr(GCClass, 'malloc_varsize_nonmovable', False): malloc_nonmovable = func_with_new_name( GCClass.malloc_varsize_nonmovable.im_func, "malloc_varsize_nonmovable") self.malloc_varsize_nonmovable_ptr = getfn( malloc_nonmovable, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True)], s_gcref) else: self.malloc_varsize_nonmovable_ptr = None if getattr(GCClass, 'malloc_varsize_resizable', False): malloc_resizable = func_with_new_name( GCClass.malloc_varsize_resizable.im_func, "malloc_varsize_resizable") self.malloc_varsize_resizable_ptr = getfn( malloc_resizable, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True)], s_gcref) else: self.malloc_varsize_resizable_ptr = None if getattr(GCClass, 'realloc', False): self.realloc_ptr = getfn( GCClass.realloc.im_func, [s_gc, s_gcref] + [annmodel.SomeInteger(nonneg=True)] * 4 + [annmodel.SomeBool()], s_gcref) if GCClass.moving_gc: self.id_ptr = getfn(GCClass.id.im_func, [s_gc, s_gcref], annmodel.SomeInteger(), inline = False, minimal_transform = False) else: self.id_ptr = None self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func, [s_gc, annmodel.SomeInteger(nonneg=True)], annmodel.s_None) if GCClass.needs_write_barrier: self.write_barrier_ptr = getfn(GCClass.write_barrier.im_func, [s_gc, annmodel.SomeAddress(), annmodel.SomeAddress()], annmodel.s_None, inline=True) else: self.write_barrier_ptr = None self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], annmodel.SomeInteger()) # experimental gc_x_* operations s_x_pool = annmodel.SomePtr(marksweep.X_POOL_PTR) s_x_clone = annmodel.SomePtr(marksweep.X_CLONE_PTR) # the x_*() methods use some regular mallocs that must be # transformed in the normal way self.x_swap_pool_ptr = getfn(GCClass.x_swap_pool.im_func, [s_gc, s_x_pool], s_x_pool, minimal_transform = False) self.x_clone_ptr = getfn(GCClass.x_clone.im_func, [s_gc, s_x_clone], annmodel.s_None, minimal_transform = False) # thread support if translator.config.translation.thread: if not hasattr(root_walker, "need_thread_support"): raise Exception("%s does not support threads" % ( root_walker.__class__.__name__,)) root_walker.need_thread_support() self.thread_prepare_ptr = getfn(root_walker.thread_prepare, [], annmodel.s_None) self.thread_run_ptr = getfn(root_walker.thread_run, [], annmodel.s_None, inline=True) self.thread_die_ptr = getfn(root_walker.thread_die, [], annmodel.s_None) annhelper.finish() # at this point, annotate all mix-level helpers annhelper.backend_optimize() self.collect_analyzer = CollectAnalyzer(self.translator) self.collect_analyzer.analyze_all() s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass) r_gc = self.translator.rtyper.getrepr(s_gc) self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc) self.malloc_zero_filled = GCClass.malloc_zero_filled HDR = self._gc_HDR = self.gcdata.gc.gcheaderbuilder.HDR self._gc_fields = fields = [] for fldname in HDR._names: FLDTYPE = getattr(HDR, fldname) fields.append(('_' + fldname, FLDTYPE))
def __init__(self, translator): from pypy.rpython.memory.gc.base import choose_gc_from_config super(FrameworkGCTransformer, self).__init__(translator, inline=True) if hasattr(self, 'GC_PARAMS'): # for tests: the GC choice can be specified as class attributes from pypy.rpython.memory.gc.marksweep import MarkSweepGC GCClass = getattr(self, 'GCClass', MarkSweepGC) GC_PARAMS = self.GC_PARAMS else: # for regular translation: pick the GC from the config GCClass, GC_PARAMS = choose_gc_from_config(translator.config) self.layoutbuilder = TransformerLayoutBuilder(self) self.get_type_id = self.layoutbuilder.get_type_id # set up dummy a table, to be overwritten with the real one in finish() type_info_table = lltype._ptr( lltype.Ptr(gctypelayout.GCData.TYPE_INFO_TABLE), "delayed!type_info_table", solid=True) gcdata = gctypelayout.GCData(type_info_table) # initialize the following two fields with a random non-NULL address, # to make the annotator happy. The fields are patched in finish() # to point to a real array. foo = lltype.malloc(lltype.FixedSizeArray(llmemory.Address, 1), immortal=True, zero=True) a_random_address = llmemory.cast_ptr_to_adr(foo) gcdata.static_root_start = a_random_address # patched in finish() gcdata.static_root_nongcend = a_random_address # patched in finish() gcdata.static_root_end = a_random_address # patched in finish() self.gcdata = gcdata self.malloc_fnptr_cache = {} gcdata.gc = GCClass(**GC_PARAMS) root_walker = self.build_root_walker() gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 self.write_barrier_calls = 0 def frameworkgc_setup(): # run-time initialization code root_walker.setup_root_walker() gcdata.gc.setup() bk = self.translator.annotator.bookkeeper # the point of this little dance is to not annotate # self.gcdata.static_root_xyz as constants. XXX is it still needed?? data_classdef = bk.getuniqueclassdef(gctypelayout.GCData) data_classdef.generalize_attr( 'static_root_start', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_nongcend', annmodel.SomeAddress()) data_classdef.generalize_attr( 'static_root_end', annmodel.SomeAddress()) annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) def getfn(ll_function, args_s, s_result, inline=False, minimal_transform=True): graph = annhelper.getgraph(ll_function, args_s, s_result) if minimal_transform: self.need_minimal_transform(graph) if inline: self.graphs_to_inline[graph] = True return annhelper.graph2const(graph) self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [], annmodel.s_None) if root_walker.need_root_stack: self.incr_stack_ptr = getfn(root_walker.incr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) self.decr_stack_ptr = getfn(root_walker.decr_stack, [annmodel.SomeInteger()], annmodel.SomeAddress(), inline = True) else: self.incr_stack_ptr = None self.decr_stack_ptr = None self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) classdef = bk.getuniqueclassdef(GCClass) s_gc = annmodel.SomeInstance(classdef) s_gcref = annmodel.SomePtr(llmemory.GCREF) malloc_fixedsize_clear_meth = GCClass.malloc_fixedsize_clear.im_func self.malloc_fixedsize_clear_ptr = getfn( malloc_fixedsize_clear_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) if hasattr(GCClass, 'malloc_fixedsize'): malloc_fixedsize_meth = GCClass.malloc_fixedsize.im_func self.malloc_fixedsize_ptr = getfn( malloc_fixedsize_meth, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) else: malloc_fixedsize_meth = None self.malloc_fixedsize_ptr = self.malloc_fixedsize_clear_ptr ## self.malloc_varsize_ptr = getfn( ## GCClass.malloc_varsize.im_func, ## [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] ## + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.malloc_varsize_clear_ptr = getfn( GCClass.malloc_varsize_clear.im_func, [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc], annmodel.s_None) # in some GCs we can inline the common case of # malloc_fixedsize(typeid, size, True, False, False) if getattr(GCClass, 'inline_simple_malloc', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside if malloc_fixedsize_meth is None: malloc_fast_meth = malloc_fixedsize_clear_meth self.malloc_fast_is_clearing = True else: malloc_fast_meth = malloc_fixedsize_meth self.malloc_fast_is_clearing = False malloc_fast = func_with_new_name( malloc_fast_meth, "malloc_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_fast_ptr = getfn( malloc_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False, s_False], s_gcref, inline = True) else: self.malloc_fast_ptr = None # in some GCs we can also inline the common case of # malloc_varsize(typeid, length, (3 constant sizes), True, False) if getattr(GCClass, 'inline_simple_malloc_varsize', False): # make a copy of this function so that it gets annotated # independently and the constants are folded inside malloc_varsize_clear_fast = func_with_new_name( GCClass.malloc_varsize_clear.im_func, "malloc_varsize_clear_fast") s_False = annmodel.SomeBool(); s_False.const = False s_True = annmodel.SomeBool(); s_True .const = True self.malloc_varsize_clear_fast_ptr = getfn( malloc_varsize_clear_fast, [s_gc, annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), s_True, s_False], s_gcref, inline = True) else: self.malloc_varsize_clear_fast_ptr = None if GCClass.moving_gc: self.id_ptr = getfn(GCClass.id.im_func, [s_gc, s_gcref], annmodel.SomeInteger(), inline = False, minimal_transform = False) else: self.id_ptr = None self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func, [s_gc, annmodel.SomeInteger(nonneg=True)], annmodel.s_None) if GCClass.needs_write_barrier: self.write_barrier_ptr = getfn(GCClass.write_barrier.im_func, [s_gc, annmodel.SomeAddress(), annmodel.SomeAddress(), annmodel.SomeAddress()], annmodel.s_None, inline=True) else: self.write_barrier_ptr = None if hasattr(GCClass, "coalloc_fixedsize_clear"): self.coalloc_clear_ptr = getfn( GCClass.coalloc_fixedsize_clear.im_func, [s_gc, annmodel.SomeAddress(), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True)], s_gcref, inline=True) self.coalloc_varsize_clear_ptr = getfn( GCClass.coalloc_varsize_clear.im_func, [s_gc, annmodel.SomeAddress()] + [annmodel.SomeInteger(nonneg=True) for i in range(5)], s_gcref, inline=True) else: self.coalloc_clear_ptr = self.coalloc_varsize_clear_ptr = None self.statistics_ptr = getfn(GCClass.statistics.im_func, [s_gc, annmodel.SomeInteger()], annmodel.SomeInteger()) # experimental gc_x_* operations s_x_pool = annmodel.SomePtr(marksweep.X_POOL_PTR) s_x_clone = annmodel.SomePtr(marksweep.X_CLONE_PTR) # the x_*() methods use some regular mallocs that must be # transformed in the normal way self.x_swap_pool_ptr = getfn(GCClass.x_swap_pool.im_func, [s_gc, s_x_pool], s_x_pool, minimal_transform = False) self.x_clone_ptr = getfn(GCClass.x_clone.im_func, [s_gc, s_x_clone], annmodel.s_None, minimal_transform = False) annhelper.finish() # at this point, annotate all mix-level helpers annhelper.backend_optimize() self.collect_analyzer = CollectAnalyzer(self.translator) self.collect_analyzer.analyze_all() s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass) r_gc = self.translator.rtyper.getrepr(s_gc) self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc) self.malloc_zero_filled = GCClass.malloc_zero_filled HDR = self._gc_HDR = self.gcdata.gc.gcheaderbuilder.HDR self._gc_fields = fields = [] for fldname in HDR._names: FLDTYPE = getattr(HDR, fldname) fields.append(('_' + fldname, FLDTYPE))
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if T is lltype.Void: return None if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if T is base_ptr_lltype(): return _opaque_list[ctypes.cast(cobj, ctypes.c_void_p).value] if isinstance(T.TO, lltype.Struct): if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) container = lltype._struct(T.TO, carray.length) else: # special treatment of 'OBJECT' subclasses if get_rtyper() and lltype._castdepth(T.TO, OBJECT) > 0: ctypes_object = get_ctypes_type(lltype.Ptr(OBJECT)) as_obj = ctypes2lltype(lltype.Ptr(OBJECT), ctypes.cast(cobj, ctypes_object)) TObj = get_rtyper().get_type_for_typeptr(as_obj.typeptr) if TObj != T.TO: ctypes_instance = get_ctypes_type(lltype.Ptr(TObj)) return lltype.cast_pointer(T, ctypes2lltype(lltype.Ptr(TObj), ctypes.cast(cobj, ctypes_instance))) container = lltype._struct(T.TO) struct_use_ctypes_storage(container, cobj.contents) elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: container = _array_of_known_length(T.TO) container._storage = cobj.contents elif isinstance(T.TO, lltype.FuncType): cobjkey = ctypes.cast(cobj, ctypes.c_void_p).value if cobjkey in _callback2obj: container = _callback2obj[cobjkey] else: _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): if T == llmemory.GCREF: # XXX obscure hack return _llgcref(cobj) else: container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is llmemory.Address: if cobj is None: llobj = llmemory.NULL else: llobj = _lladdress(cobj) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) elif T is lltype.Void: llobj = cobj else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if T is lltype.Void: return None if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if T is base_ptr_lltype(): return _opaque_list[ctypes.cast(cobj, ctypes.c_void_p).value] if isinstance(T.TO, lltype.Struct): if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) container = lltype._struct(T.TO, carray.length) else: # special treatment of 'OBJECT' subclasses if get_rtyper() and lltype._castdepth(T.TO, OBJECT) > 0: ctypes_object = get_ctypes_type(lltype.Ptr(OBJECT)) as_obj = ctypes2lltype(lltype.Ptr(OBJECT), ctypes.cast(cobj, ctypes_object)) TObj = get_rtyper().get_type_for_typeptr(as_obj.typeptr) if TObj != T.TO: ctypes_instance = get_ctypes_type(lltype.Ptr(TObj)) return lltype.cast_pointer( T, ctypes2lltype(lltype.Ptr(TObj), ctypes.cast(cobj, ctypes_instance))) container = lltype._struct(T.TO) struct_use_ctypes_storage(container, cobj.contents) addr = ctypes.addressof(cobj.contents) if addr in _parent_cache: setparentstructure(container, _parent_cache[addr]) elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: container = _array_of_known_length(T.TO) container._storage = cobj.contents elif isinstance(T.TO, lltype.FuncType): cobjkey = ctypes.cast(cobj, ctypes.c_void_p).value if cobjkey in _callback2obj: container = _callback2obj[cobjkey] else: _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): if T == llmemory.GCREF: container = _llgcopaque(cobj) else: container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is llmemory.Address: if cobj is None: llobj = llmemory.NULL else: llobj = _lladdress(cobj) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.Bool: assert cobj == True or cobj == False # 0 and 1 work too llobj = bool(cobj) elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) elif T is lltype.Void: llobj = cobj else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj
def ctypes2lltype(T, cobj): """Convert the ctypes object 'cobj' to its lltype equivalent. 'T' is the expected lltype type. """ if T is lltype.Void: return None if isinstance(T, lltype.Ptr): if not cobj: # NULL pointer return lltype.nullptr(T.TO) if isinstance(T.TO, lltype.Struct): REAL_TYPE = T.TO if T.TO._arrayfld is not None: carray = getattr(cobj.contents, T.TO._arrayfld) container = lltype._struct(T.TO, carray.length) else: # special treatment of 'OBJECT' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT) >= 0: # figure out the real type of the object containerheader = lltype._struct(OBJECT) cobjheader = ctypes.cast( cobj, get_ctypes_type(lltype.Ptr(OBJECT))) struct_use_ctypes_storage(containerheader, cobjheader.contents) REAL_TYPE = get_rtyper().get_type_for_typeptr( containerheader.typeptr) REAL_T = lltype.Ptr(REAL_TYPE) cobj = ctypes.cast(cobj, get_ctypes_type(REAL_T)) container = lltype._struct(REAL_TYPE) struct_use_ctypes_storage(container, cobj.contents) if REAL_TYPE != T.TO: p = container._as_ptr() container = lltype.cast_pointer(T, p)._as_obj() # special treatment of 'OBJECT_VTABLE' subclasses if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT_VTABLE) >= 0: # figure out the real object that this vtable points to, # and just return that p = get_rtyper().get_real_typeptr_for_typeptr( container._as_ptr()) container = lltype.cast_pointer(T, p)._as_obj() elif isinstance(T.TO, lltype.Array): if T.TO._hints.get('nolength', False): container = _array_of_unknown_length(T.TO) container._storage = cobj.contents else: container = _array_of_known_length(T.TO) container._storage = cobj.contents elif isinstance(T.TO, lltype.FuncType): cobjkey = ctypes.cast(cobj, ctypes.c_void_p).value if cobjkey in _callback2obj: container = _callback2obj[cobjkey] else: _callable = get_ctypes_trampoline(T.TO, cobj) return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'), _callable=_callable) elif isinstance(T.TO, lltype.OpaqueType): if T == llmemory.GCREF: container = _llgcopaque(cobj) else: container = lltype._opaque(T.TO) else: raise NotImplementedError(T) llobj = lltype._ptr(T, container, solid=True) elif T is llmemory.Address: if cobj is None: llobj = llmemory.NULL else: llobj = _lladdress(cobj) elif T is lltype.Char: llobj = chr(cobj) elif T is lltype.UniChar: llobj = unichr(cobj) elif T is lltype.Signed: llobj = cobj elif T is lltype.Bool: assert cobj == True or cobj == False # 0 and 1 work too llobj = bool(cobj) elif T is lltype.SingleFloat: if isinstance(cobj, ctypes.c_float): cobj = cobj.value llobj = r_singlefloat(cobj) elif T is lltype.Void: llobj = cobj else: from pypy.rpython.lltypesystem import rffi try: inttype = rffi.platform.numbertype_to_rclass[T] except KeyError: llobj = cobj else: llobj = inttype(cobj) assert lltype.typeOf(llobj) == T return llobj