Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r82023:f3b48b1063f6 Date: 2016-02-01 09:11 +0100 http://bitbucket.org/pypy/pypy/changeset/f3b48b1063f6/
Log: catchup with default diff too long, truncating to 2000 out of 2165 lines diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -54,7 +54,8 @@ It is quite common nowadays that xyz is available on PyPI_ and installable with ``pip install xyz``. The simplest solution is to `use virtualenv (as documented here)`_. Then enter (activate) the virtualenv -and type: ``pip install xyz``. +and type: ``pip install xyz``. If you don't know or don't want virtualenv, +you can also install ``pip`` globally by saying ``pypy -m ensurepip``. If you get errors from the C compiler, the module is a CPython C Extension module using unsupported features. `See below.`_ diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -133,6 +133,13 @@ `rpython/jit/metainterp/optimizeopt/pure.py`, which can result in better codegen for traces containing a large number of pure getfield operations. +.. branch: exctrans + +Try to ensure that no new functions get annotated during the 'source_c' phase. +Refactor sandboxing to operate at a higher level. + +.. branch: cpyext-bootstrap + .. branch: memop-simplify3 Further simplifying the backend operations malloc_cond_varsize and zero_array. diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -36,7 +36,6 @@ import pypy.module.cpyext.object import pypy.module.cpyext.stringobject import pypy.module.cpyext.tupleobject -import pypy.module.cpyext.ndarrayobject import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject import pypy.module.cpyext.intobject diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -143,7 +143,7 @@ target.chmod(0444) # make the file read-only, to make sure that nobody # edits it by mistake -def copy_header_files(dstdir): +def copy_header_files(dstdir, copy_numpy_headers): # XXX: 20 lines of code to recursively copy a directory, really?? assert dstdir.check(dir=True) headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl') @@ -151,15 +151,16 @@ headers.append(udir.join(name)) _copy_header_files(headers, dstdir) - try: - dstdir.mkdir('numpy') - except py.error.EEXIST: - pass - numpy_dstdir = dstdir / 'numpy' + if copy_numpy_headers: + try: + dstdir.mkdir('numpy') + except py.error.EEXIST: + pass + numpy_dstdir = dstdir / 'numpy' - numpy_include_dir = include_dir / 'numpy' - numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl') - _copy_header_files(numpy_headers, numpy_dstdir) + numpy_include_dir = include_dir / 'numpy' + numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl') + _copy_header_files(numpy_headers, numpy_dstdir) class NotSpecified(object): @@ -442,8 +443,8 @@ TYPES = {} GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur '_Py_NoneStruct#': ('PyObject*', 'space.w_None'), - '_Py_TrueStruct#': ('PyObject*', 'space.w_True'), - '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'), + '_Py_TrueStruct#': ('PyIntObject*', 'space.w_True'), + '_Py_ZeroStruct#': ('PyIntObject*', 'space.w_False'), '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'), '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'), 'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'), @@ -482,7 +483,6 @@ "PyComplex_Type": "space.w_complex", "PyByteArray_Type": "space.w_bytearray", "PyMemoryView_Type": "space.w_memoryview", - "PyArray_Type": "space.gettypeobject(W_NDimArray.typedef)", "PyBaseObject_Type": "space.w_object", 'PyNone_Type': 'space.type(space.w_None)', 'PyNotImplemented_Type': 'space.type(space.w_NotImplemented)', @@ -506,7 +506,9 @@ def get_structtype_for_ctype(ctype): from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr from pypy.module.cpyext.cdatetime import PyDateTime_CAPI + from pypy.module.cpyext.intobject import PyIntObject return {"PyObject*": PyObject, "PyTypeObject*": PyTypeObjectPtr, + "PyIntObject*": PyIntObject, "PyDateTime_CAPI*": lltype.Ptr(PyDateTime_CAPI)}[ctype] PyTypeObject = lltype.ForwardReference() @@ -771,6 +773,8 @@ "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref + use_micronumpy = setup_micronumpy(space) + export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from rpython.translator.c.database import LowLevelDatabase db = LowLevelDatabase() @@ -828,6 +832,7 @@ space.fromcache(State).install_dll(eci) # populate static data + builder = StaticObjectBuilder(space) for name, (typ, expr) in GLOBALS.iteritems(): from pypy.module import cpyext w_obj = eval(expr) @@ -852,7 +857,7 @@ assert False, "Unknown static pointer: %s %s" % (typ, name) ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value), ctypes.c_void_p).value - elif typ in ('PyObject*', 'PyTypeObject*'): + elif typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'): if name.startswith('PyPyExc_') or name.startswith('cpyexttestExc_'): # we already have the pointer in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name) @@ -861,17 +866,10 @@ # we have a structure, get its address in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll)) - from pypy.module.cpyext.pyobject import ( - track_reference, get_typedescr) - w_type = space.type(w_obj) - typedescr = get_typedescr(w_type.instancetypedef) - py_obj.c_ob_refcnt = 1 - py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, - make_ref(space, w_type)) - typedescr.attach(space, py_obj, w_obj) - track_reference(space, py_obj, w_obj) + builder.prepare(py_obj, w_obj) else: assert False, "Unknown static object: %s %s" % (typ, name) + builder.attach_all() pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI') @@ -888,6 +886,36 @@ setup_init_functions(eci, translating=False) return modulename.new(ext='') + +class StaticObjectBuilder: + def __init__(self, space): + self.space = space + self.to_attach = [] + + def prepare(self, py_obj, w_obj): + from pypy.module.cpyext.pyobject import track_reference + py_obj.c_ob_refcnt = 1 + track_reference(self.space, py_obj, w_obj) + self.to_attach.append((py_obj, w_obj)) + + def attach_all(self): + from pypy.module.cpyext.pyobject import get_typedescr, make_ref + from pypy.module.cpyext.typeobject import finish_type_1, finish_type_2 + space = self.space + space._cpyext_type_init = [] + for py_obj, w_obj in self.to_attach: + w_type = space.type(w_obj) + typedescr = get_typedescr(w_type.instancetypedef) + py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, + make_ref(space, w_type)) + typedescr.attach(space, py_obj, w_obj) + cpyext_type_init = space._cpyext_type_init + del space._cpyext_type_init + for pto, w_type in cpyext_type_init: + finish_type_1(space, pto) + finish_type_2(space, pto, w_type) + + def mangle_name(prefix, name): if name.startswith('Py'): return prefix + name[2:] @@ -983,6 +1011,24 @@ pypy_decl_h.write('\n'.join(pypy_decls)) return functions +separate_module_files = [source_dir / "varargwrapper.c", + source_dir / "pyerrors.c", + source_dir / "modsupport.c", + source_dir / "getargs.c", + source_dir / "abstract.c", + source_dir / "stringobject.c", + source_dir / "mysnprintf.c", + source_dir / "pythonrun.c", + source_dir / "sysmodule.c", + source_dir / "bufferobject.c", + source_dir / "cobject.c", + source_dir / "structseq.c", + source_dir / "capsule.c", + source_dir / "pysignals.c", + source_dir / "pythread.c", + source_dir / "missing.c", + ] + def build_eci(building_bridge, export_symbols, code): "NOT_RPYTHON" # Build code and get pointer to the structure @@ -1036,24 +1082,7 @@ eci = ExternalCompilationInfo( include_dirs=include_dirs, - separate_module_files=[source_dir / "varargwrapper.c", - source_dir / "pyerrors.c", - source_dir / "modsupport.c", - source_dir / "getargs.c", - source_dir / "abstract.c", - source_dir / "stringobject.c", - source_dir / "mysnprintf.c", - source_dir / "pythonrun.c", - source_dir / "sysmodule.c", - source_dir / "bufferobject.c", - source_dir / "cobject.c", - source_dir / "structseq.c", - source_dir / "capsule.c", - source_dir / "pysignals.c", - source_dir / "pythread.c", - source_dir / "ndarrayobject.c", - source_dir / "missing.c", - ], + separate_module_files= separate_module_files, separate_module_sources=separate_module_sources, compile_extra=compile_extra, **kwds @@ -1061,10 +1090,22 @@ return eci +def setup_micronumpy(space): + use_micronumpy = space.config.objspace.usemodules.micronumpy + if not use_micronumpy: + return use_micronumpy + # import to register api functions by side-effect + import pypy.module.cpyext.ndarrayobject + global GLOBALS, SYMBOLS_C, separate_module_files + GLOBALS["PyArray_Type#"]= ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)") + SYMBOLS_C += ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS'] + separate_module_files.append(source_dir / "ndarrayobject.c") + return use_micronumpy def setup_library(space): "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref + use_micronumpy = setup_micronumpy(space) export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from rpython.translator.c.database import LowLevelDatabase @@ -1082,14 +1123,33 @@ run_bootstrap_functions(space) setup_va_functions(eci) + from pypy.module import cpyext # for eval() below + + # Set up the types. Needs a special case, because of the + # immediate cycle involving 'c_ob_type', and because we don't + # want these types to be Py_TPFLAGS_HEAPTYPE. + static_types = {} + for name, (typ, expr) in GLOBALS.items(): + if typ == 'PyTypeObject*': + pto = lltype.malloc(PyTypeObject, immortal=True, + zero=True, flavor='raw') + pto.c_ob_refcnt = 1 + pto.c_tp_basicsize = -1 + static_types[name] = pto + builder = StaticObjectBuilder(space) + for name, pto in static_types.items(): + pto.c_ob_type = static_types['PyType_Type#'] + w_type = eval(GLOBALS[name][1]) + builder.prepare(rffi.cast(PyObject, pto), w_type) + builder.attach_all() + # populate static data for name, (typ, expr) in GLOBALS.iteritems(): name = name.replace("#", "") if name.startswith('PyExc_'): name = '_' + name - from pypy.module import cpyext w_obj = eval(expr) - if typ in ('PyObject*', 'PyTypeObject*'): + if typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'): struct_ptr = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': continue @@ -1106,7 +1166,7 @@ setup_init_functions(eci, translating=True) trunk_include = pypydir.dirpath() / 'include' - copy_header_files(trunk_include) + copy_header_files(trunk_include, use_micronumpy) def _load_from_cffi(space, name, path, initptr): from pypy.module._cffi_backend import cffi1_module diff --git a/pypy/module/cpyext/include/stringobject.h b/pypy/module/cpyext/include/stringobject.h --- a/pypy/module/cpyext/include/stringobject.h +++ b/pypy/module/cpyext/include/stringobject.h @@ -7,8 +7,8 @@ extern "C" { #endif -#define PyString_GET_SIZE(op) PyString_Size(op) -#define PyString_AS_STRING(op) PyString_AsString(op) +#define PyString_GET_SIZE(op) PyString_Size((PyObject*)(op)) +#define PyString_AS_STRING(op) PyString_AsString((PyObject*)(op)) typedef struct { PyObject_HEAD diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py --- a/pypy/module/cpyext/test/test_api.py +++ b/pypy/module/cpyext/test/test_api.py @@ -98,7 +98,7 @@ def test_copy_header_files(tmpdir): - api.copy_header_files(tmpdir) + api.copy_header_files(tmpdir, True) def check(name): f = tmpdir.join(name) assert f.check(file=True) diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -374,6 +374,11 @@ module = self.import_extension('foo', [ ("test_type", "METH_O", ''' + /* "args->ob_type" is a strange way to get at 'type', + which should have a different tp_getattro/tp_setattro + than its tp_base, which is 'object'. + */ + if (!args->ob_type->tp_setattro) { PyErr_SetString(PyExc_ValueError, "missing tp_setattro"); @@ -382,8 +387,12 @@ if (args->ob_type->tp_setattro == args->ob_type->tp_base->tp_setattro) { - PyErr_SetString(PyExc_ValueError, "recursive tp_setattro"); - return NULL; + /* Note that unlike CPython, in PyPy 'type.tp_setattro' + is the same function as 'object.tp_setattro'. This + test used to check that it was not, but that was an + artifact of the bootstrap logic only---in the final + C sources I checked and they are indeed the same. + So we ignore this problem here. */ } if (!args->ob_type->tp_getattro) { diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -146,7 +146,7 @@ assert len(slot_names) == 2 struct = getattr(pto, slot_names[0]) if not struct: - assert not space.config.translating + #assert not space.config.translating assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE if slot_names[0] == 'c_tp_as_number': STRUCT_TYPE = PyNumberMethods @@ -310,55 +310,6 @@ realize=type_realize, dealloc=type_dealloc) - # some types are difficult to create because of cycles. - # - object.ob_type = type - # - type.ob_type = type - # - tuple.ob_type = type - # - type.tp_base = object - # - tuple.tp_base = object - # - type.tp_bases is a tuple - # - object.tp_bases is a tuple - # - tuple.tp_bases is a tuple - - # insert null placeholders to please create_ref() - track_reference(space, lltype.nullptr(PyObject.TO), space.w_type) - track_reference(space, lltype.nullptr(PyObject.TO), space.w_object) - track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple) - track_reference(space, lltype.nullptr(PyObject.TO), space.w_str) - - # create the objects - py_type = create_ref(space, space.w_type) - py_object = create_ref(space, space.w_object) - py_tuple = create_ref(space, space.w_tuple) - py_str = create_ref(space, space.w_str) - # XXX py_str is not initialized here correctly, because we are - # not tracking it, it gets an empty c_ob_type from py_basestring - - # form cycles - pto_type = rffi.cast(PyTypeObjectPtr, py_type) - py_type.c_ob_type = pto_type - py_object.c_ob_type = pto_type - py_tuple.c_ob_type = pto_type - - pto_object = rffi.cast(PyTypeObjectPtr, py_object) - pto_type.c_tp_base = pto_object - pto_tuple = rffi.cast(PyTypeObjectPtr, py_tuple) - pto_tuple.c_tp_base = pto_object - - pto_type.c_tp_bases.c_ob_type = pto_tuple - pto_object.c_tp_bases.c_ob_type = pto_tuple - pto_tuple.c_tp_bases.c_ob_type = pto_tuple - - for typ in (py_type, py_object, py_tuple, py_str): - heaptype = rffi.cast(PyHeapTypeObject, typ) - heaptype.c_ht_name.c_ob_type = pto_type - - # Restore the mapping - track_reference(space, py_type, space.w_type, replace=True) - track_reference(space, py_object, space.w_object, replace=True) - track_reference(space, py_tuple, space.w_tuple, replace=True) - track_reference(space, py_str, space.w_str, replace=True) - @cpython_api([PyObject], lltype.Void, external=False) def subtype_dealloc(space, obj): @@ -476,6 +427,8 @@ pto.c_tp_as_sequence = heaptype.c_as_sequence pto.c_tp_as_mapping = heaptype.c_as_mapping pto.c_tp_as_buffer = heaptype.c_as_buffer + pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out + pto.c_tp_itemsize = 0 return rffi.cast(PyObject, heaptype) @@ -511,8 +464,6 @@ pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) else: pto.c_tp_name = rffi.str2charp(w_type.name) - pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out - pto.c_tp_itemsize = 0 # uninitialized fields: # c_tp_print, c_tp_getattr, c_tp_setattr # XXX implement @@ -520,8 +471,11 @@ w_base = best_base(space, w_type.bases_w) pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base)) - finish_type_1(space, pto) - finish_type_2(space, pto, w_type) + if hasattr(space, '_cpyext_type_init'): + space._cpyext_type_init.append((pto, w_type)) + else: + finish_type_1(space, pto) + finish_type_2(space, pto, w_type) pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct) if pto.c_tp_base: diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -116,7 +116,7 @@ def _find_map_attr(self, name, index): while isinstance(self, PlainAttribute): - if name == self.name and index == self.index: + if index == self.index and name == self.name: return self self = self.back return None @@ -156,7 +156,6 @@ jit.isconstant(name) and jit.isconstant(index)) def add_attr(self, obj, name, index, w_value): - # grumble, jit needs this attr = self._get_new_attr(name, index) oldattr = obj._get_mapdict_map() if not jit.we_are_jitted(): @@ -296,7 +295,7 @@ new_obj._get_mapdict_map().add_attr(new_obj, self.name, self.index, w_value) def delete(self, obj, name, index): - if name == self.name and index == self.index: + if index == self.index and name == self.name: # ok, attribute is deleted if not self.ever_mutated: self.ever_mutated = True diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -942,7 +942,7 @@ return False if w_set.length() == 0: return True - # it's possible to have 0-lenght strategy that's not empty + # it's possible to have 0-length strategy that's not empty if w_set.strategy is w_other.strategy: return self._issubset_unwrapped(w_set, w_other) if not self.may_contain_equal_elements(w_other.strategy): diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py --- a/rpython/memory/gctransform/boehm.py +++ b/rpython/memory/gctransform/boehm.py @@ -74,7 +74,7 @@ def gct_fv_gc_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size, c_offset_to_length): - # XXX same behavior for zero=True: in theory that's wrong + # XXX same behavior for zero=True: in theory that's wrong if c_offset_to_length is None: v_raw = hop.genop("direct_call", [self.malloc_varsize_no_length_ptr, v_length, @@ -156,6 +156,11 @@ resulttype = lltype.Signed) hop.genop('int_invert', [v_int], resultvar=hop.spaceop.result) + def gcheader_initdata(self, defnode): + hdr = lltype.malloc(self.HDR, immortal=True) + hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr()) + return hdr._obj + ########## weakrefs ########## # Boehm: weakref objects are small structures containing only a Boehm diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -288,7 +288,6 @@ s_gcref = SomePtr(llmemory.GCREF) gcdata = self.gcdata - translator = self.translator #use the GC flag to find which malloc method to use #malloc_zero_filled == Ture -> malloc_fixedsize/varsize_clear #malloc_zero_filled == Flase -> malloc_fixedsize/varsize @@ -322,7 +321,7 @@ GCClass.malloc_varsize.im_func, [s_gc, s_typeid16] + [annmodel.SomeInteger(nonneg=True) for i in range(4)], s_gcref) - + self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc, annmodel.SomeInteger()], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, @@ -1385,7 +1384,7 @@ [v] + previous_steps + [c_name, c_null]) else: llops.genop('bare_setfield', [v, c_name, c_null]) - + return elif isinstance(TYPE, lltype.Array): ITEM = TYPE.OF @@ -1412,6 +1411,25 @@ resulttype=llmemory.Address) llops.genop('raw_memclear', [v_adr, v_totalsize]) + def gcheader_initdata(self, defnode): + o = lltype.top_container(defnode.obj) + needs_hash = self.get_prebuilt_hash(o) is not None + hdr = self.gc_header_for(o, needs_hash) + return hdr._obj + + def get_prebuilt_hash(self, obj): + # for prebuilt objects that need to have their hash stored and + # restored. Note that only structures that are StructNodes all + # the way have their hash stored (and not e.g. structs with var- + # sized arrays at the end). 'obj' must be the top_container. + TYPE = lltype.typeOf(obj) + if not isinstance(TYPE, lltype.GcStruct): + return None + if TYPE._is_varsize(): + return None + return getattr(obj, '_hash_cache_', None) + + class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder): diff --git a/rpython/memory/gctransform/refcounting.py b/rpython/memory/gctransform/refcounting.py --- a/rpython/memory/gctransform/refcounting.py +++ b/rpython/memory/gctransform/refcounting.py @@ -285,3 +285,7 @@ resulttype=llmemory.Address) hop.genop("direct_call", [self.identityhash_ptr, v_adr], resultvar=hop.spaceop.result) + + def gcheader_initdata(self, defnode): + top = lltype.top_container(defnode.obj) + return self.gcheaderbuilder.header_of_object(top)._obj diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py --- a/rpython/memory/gctransform/test/test_framework.py +++ b/rpython/memory/gctransform/test/test_framework.py @@ -40,7 +40,7 @@ t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) - db = cbuild.generate_graphs_for_llinterp() + db = cbuild.build_database() entrypointptr = cbuild.getentrypointptr() entrygraph = entrypointptr._obj.graph @@ -69,7 +69,7 @@ return -x t = rtype(g, [int]) gg = graphof(t, g) - assert not CollectAnalyzer(t).analyze_direct_call(gg) + assert not CollectAnalyzer(t).analyze_direct_call(gg) def test_cancollect_external(): fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=False) @@ -110,12 +110,12 @@ def entrypoint(argv): return g() + 2 - + t = rtype(entrypoint, [s_list_of_strings]) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) - db = cbuild.generate_graphs_for_llinterp() + db = cbuild.build_database() def test_no_collect_detection(): from rpython.rlib import rgc @@ -134,12 +134,13 @@ def entrypoint(argv): return g() + 2 - + t = rtype(entrypoint, [s_list_of_strings]) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) - f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp) + with py.test.raises(Exception) as f: + cbuild.build_database() expected = "'no_collect' function can trigger collection: <function g at " assert str(f.value).startswith(expected) @@ -163,11 +164,12 @@ t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, entrypoint, t.config, gcpolicy=FrameworkGcPolicy2) - f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp) + with py.test.raises(Exception) as f: + cbuild.build_database() assert 'can cause the GC to be called' in str(f.value) assert 'trace_func' in str(f.value) assert 'MyStructure' in str(f.value) - + class WriteBarrierTransformer(ShadowStackFrameworkGCTransformer): clean_sets = {} GC_PARAMS = {} @@ -252,7 +254,7 @@ t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, g, t.config, gcpolicy=FrameworkGcPolicy2) - db = cbuild.generate_graphs_for_llinterp() + db = cbuild.build_database() ff = graphof(t, f) #ff.show() @@ -306,7 +308,7 @@ def test_find_clean_setarrayitems(): S = lltype.GcStruct('S') A = lltype.GcArray(lltype.Ptr(S)) - + def f(): l = lltype.malloc(A, 3) l[0] = lltype.malloc(S) @@ -327,7 +329,7 @@ def test_find_clean_setarrayitems_2(): S = lltype.GcStruct('S') A = lltype.GcArray(lltype.Ptr(S)) - + def f(): l = lltype.malloc(A, 3) l[0] = lltype.malloc(S) @@ -349,7 +351,7 @@ def test_find_clean_setarrayitems_3(): S = lltype.GcStruct('S') A = lltype.GcArray(lltype.Ptr(S)) - + def f(): l = lltype.malloc(A, 3) l[0] = lltype.malloc(S) diff --git a/rpython/memory/gctransform/test/test_transform.py b/rpython/memory/gctransform/test/test_transform.py --- a/rpython/memory/gctransform/test/test_transform.py +++ b/rpython/memory/gctransform/test/test_transform.py @@ -16,7 +16,7 @@ t = rtype(f, args_s) # XXX we shouldn't need an actual gcpolicy here. cbuild = CStandaloneBuilder(t, f, t.config, gcpolicy=self.gcpolicy) - cbuild.generate_graphs_for_llinterp() + cbuild.build_database() graph = cbuild.getentrypointptr()._obj.graph # arguments cannot be GC objects because nobody would put a # proper header on them diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py --- a/rpython/memory/gctransform/transform.py +++ b/rpython/memory/gctransform/transform.py @@ -113,21 +113,14 @@ self.seen_graphs.add(graph) self.minimal_transform.add(graph) - def prepare_inline_helpers(self, graphs): + def inline_helpers(self, graphs): from rpython.translator.backendopt.inline import iter_callsites + raise_analyzer = RaiseAnalyzer(self.translator) for graph in graphs: - self.graph_dependencies[graph] = {} + to_enum = [] for called, block, i in iter_callsites(graph, None): if called in self.graphs_to_inline: - self.graph_dependencies[graph][called] = True - self.prepared = True - - def inline_helpers(self, graph): - if not self.prepared: - raise Exception("Need to call prepare_inline_helpers first") - if self.inline: - raise_analyzer = RaiseAnalyzer(self.translator) - to_enum = self.graph_dependencies.get(graph, self.graphs_to_inline) + to_enum.append(called) must_constfold = False for inline_graph in to_enum: try: @@ -378,6 +371,10 @@ return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP), lltype.nullptr(ARRAY_TYPEID_MAP))) + def get_prebuilt_hash(self, obj): + return None + + class MinimalGCTransformer(BaseGCTransformer): def __init__(self, parenttransformer): BaseGCTransformer.__init__(self, parenttransformer.translator) diff --git a/rpython/memory/test/test_transformed_gc.py b/rpython/memory/test/test_transformed_gc.py --- a/rpython/memory/test/test_transformed_gc.py +++ b/rpython/memory/test/test_transformed_gc.py @@ -110,7 +110,7 @@ cbuild = CStandaloneBuilder(t, entrypoint, config=t.config, gcpolicy=cls.gcpolicy) - db = cbuild.generate_graphs_for_llinterp() + db = cbuild.build_database() entrypointptr = cbuild.getentrypointptr() entrygraph = entrypointptr._obj.graph if option.view: @@ -1071,7 +1071,7 @@ def test_adr_of_nursery(self): run = self.runner("adr_of_nursery") res = run([]) - + class TestGenerationalNoFullCollectGC(GCTest): # test that nursery is doing its job and that no full collection @@ -1131,7 +1131,7 @@ 'large_object': 8*WORD, 'translated_to_c': False} root_stack_depth = 200 - + def define_ref_from_rawmalloced_to_regular(cls): import gc S = lltype.GcStruct('S', ('x', lltype.Signed)) @@ -1182,7 +1182,7 @@ run = self.runner("write_barrier_direct") res = run([]) assert res == 42 - + class TestMiniMarkGC(TestHybridGC): gcname = "minimark" GC_CAN_TEST_ID = True @@ -1199,7 +1199,7 @@ 'translated_to_c': False, } root_stack_depth = 200 - + def define_no_clean_setarrayitems(cls): # The optimization find_clean_setarrayitems() in # gctransformer/framework.py does not work with card marking. @@ -1224,7 +1224,7 @@ run = self.runner("no_clean_setarrayitems") res = run([]) assert res == 123 - + def define_nursery_hash_base(cls): class A: pass @@ -1283,19 +1283,19 @@ 'translated_to_c': False, } root_stack_depth = 200 - + def define_malloc_array_of_gcptr(self): S = lltype.GcStruct('S', ('x', lltype.Signed)) A = lltype.GcArray(lltype.Ptr(S)) def f(): lst = lltype.malloc(A, 5) - return (lst[0] == lltype.nullptr(S) + return (lst[0] == lltype.nullptr(S) and lst[1] == lltype.nullptr(S) and lst[2] == lltype.nullptr(S) and lst[3] == lltype.nullptr(S) and lst[4] == lltype.nullptr(S)) return f - + def test_malloc_array_of_gcptr(self): run = self.runner('malloc_array_of_gcptr') res = run([]) @@ -1376,7 +1376,7 @@ def define_gettypeid(cls): class A(object): pass - + def fn(): a = A() return rgc.get_typeid(a) diff --git a/rpython/rtyper/extfunc.py b/rpython/rtyper/extfunc.py --- a/rpython/rtyper/extfunc.py +++ b/rpython/rtyper/extfunc.py @@ -46,6 +46,12 @@ impl = getattr(self, 'lltypeimpl', None) fakeimpl = getattr(self, 'lltypefakeimpl', self.instance) if impl: + if (rtyper.annotator.translator.config.translation.sandbox + and not self.safe_not_sandboxed): + from rpython.translator.sandbox.rsandbox import ( + make_sandbox_trampoline) + impl = make_sandbox_trampoline( + self.name, signature_args, s_result) if hasattr(self, 'lltypefakeimpl'): # If we have both an llimpl and an llfakeimpl, # we need a wrapper that selects the proper one and calls it @@ -74,15 +80,10 @@ return original_impl(%s) """ % (args, args, args)) in d impl = func_with_new_name(d['ll_wrapper'], name + '_wrapper') - if rtyper.annotator.translator.config.translation.sandbox: - impl._dont_inline_ = True # store some attributes to the 'impl' function, where # the eventual call to rtyper.getcallable() will find them # and transfer them to the final lltype.functionptr(). - impl._llfnobjattrs_ = { - '_name': self.name, - '_safe_not_sandboxed': self.safe_not_sandboxed, - } + impl._llfnobjattrs_ = {'_name': self.name} obj = rtyper.getannmixlevel().delayedfunction( impl, signature_args, hop.s_result) else: diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py --- a/rpython/rtyper/rclass.py +++ b/rpython/rtyper/rclass.py @@ -13,8 +13,9 @@ from rpython.rtyper.lltypesystem.lltype import ( Ptr, Struct, GcStruct, malloc, cast_pointer, castable, nullptr, RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, Void, FuncType, Bool, Signed, - functionptr) + functionptr, attachRuntimeTypeInfo) from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.rtyper.llannotation import SomePtr from rpython.rtyper.lltypesystem import rstr from rpython.rtyper.rmodel import ( Repr, getgcflavor, inputconst, warning, mangle) @@ -590,10 +591,17 @@ _callable=graph.func) else: destrptr = None - OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]] - self.rtyper.attachRuntimeTypeInfoFunc(self.object_type, - ll_runtime_type_info, - OBJECT, destrptr) + self.rtyper.call_all_setups() # compute ForwardReferences now + args_s = [SomePtr(Ptr(OBJECT))] + graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s) + s = self.rtyper.annotation(graph.getreturnvar()) + if (not isinstance(s, SomePtr) or + s.ll_ptrtype != Ptr(RuntimeTypeInfo)): + raise TyperError("runtime type info function returns %r, " + "expected Ptr(RuntimeTypeInfo)" % (s)) + funcptr = self.rtyper.getcallable(graph) + attachRuntimeTypeInfo(self.object_type, funcptr, destrptr) + vtable = self.rclass.getvtable() self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO) diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py --- a/rpython/rtyper/rtyper.py +++ b/rpython/rtyper/rtyper.py @@ -1,14 +1,14 @@ """ RTyper: converts high-level operations into low-level operations in flow graphs. -The main class, with code to walk blocks and dispatch individual operations -to the care of the rtype_*() methods implemented in the other r* modules. -For each high-level operation 'hop', the rtype_*() methods produce low-level -operations that are collected in the 'llops' list defined here. When necessary, -conversions are inserted. +The main class, with code to walk blocks and dispatch individual operations to +the care of the rtype_*() methods implemented in the other r* modules. For +each high-level operation 'hop', the rtype_*() methods produce low-level +operations that are collected in the 'llops' list defined here. When +necessary, conversions are inserted. -This logic borrows a bit from rpython.annotator.annrpython, without the fixpoint -computation part. +This logic borrows a bit from rpython.annotator.annrpython, without the +fixpoint computation part. """ import os @@ -16,19 +16,20 @@ import py, math from rpython.annotator import model as annmodel, unaryop, binaryop -from rpython.rtyper.llannotation import SomePtr, lltype_to_annotation +from rpython.rtyper.llannotation import lltype_to_annotation from rpython.flowspace.model import Variable, Constant, SpaceOperation -from rpython.rtyper.annlowlevel import annotate_lowlevel_helper, LowLevelAnnotatorPolicy +from rpython.rtyper.annlowlevel import ( + annotate_lowlevel_helper, LowLevelAnnotatorPolicy) from rpython.rtyper.error import TyperError from rpython.rtyper.exceptiondata import ExceptionData from rpython.rtyper.lltypesystem.lltype import (Signed, Void, LowLevelType, - Ptr, ContainerType, FuncType, typeOf, RuntimeTypeInfo, - attachRuntimeTypeInfo, Primitive, getfunctionptr) -from rpython.rtyper.rmodel import Repr, inputconst, BrokenReprTyperError + ContainerType, typeOf, Primitive, getfunctionptr) +from rpython.rtyper.rmodel import Repr, inputconst from rpython.rtyper import rclass from rpython.rtyper.rclass import RootClassRepr from rpython.tool.pairtype import pair from rpython.translator.unsimplify import insert_empty_block +from rpython.translator.sandbox.rsandbox import make_sandbox_trampoline class RPythonTyper(object): @@ -561,6 +562,17 @@ def getcallable(self, graph): def getconcretetype(v): return self.bindingrepr(v).lowleveltype + if self.annotator.translator.config.translation.sandbox: + try: + name = graph.func._sandbox_external_name + except AttributeError: + pass + else: + args_s = [v.annotation for v in graph.getargs()] + s_result = graph.getreturnvar().annotation + sandboxed = make_sandbox_trampoline(name, args_s, s_result) + return self.getannmixlevel().delayedfunction( + sandboxed, args_s, s_result) return getfunctionptr(graph, getconcretetype) @@ -590,21 +602,6 @@ graph = self.annotate_helper(ll_function, argtypes) return self.getcallable(graph) - def attachRuntimeTypeInfoFunc(self, GCSTRUCT, func, ARG_GCSTRUCT=None, - destrptr=None): - self.call_all_setups() # compute ForwardReferences now - if ARG_GCSTRUCT is None: - ARG_GCSTRUCT = GCSTRUCT - args_s = [SomePtr(Ptr(ARG_GCSTRUCT))] - graph = self.annotate_helper(func, args_s) - s = self.annotation(graph.getreturnvar()) - if (not isinstance(s, SomePtr) or - s.ll_ptrtype != Ptr(RuntimeTypeInfo)): - raise TyperError("runtime type info function %r returns %r, " - "excepted Ptr(RuntimeTypeInfo)" % (func, s)) - funcptr = self.getcallable(graph) - attachRuntimeTypeInfo(GCSTRUCT, funcptr, destrptr) - # register operations from annotation model RPythonTyper._registeroperations(unaryop.UNARY_OPERATIONS, binaryop.BINARY_OPERATIONS) diff --git a/rpython/rtyper/tool/test/test_rffi_platform.py b/rpython/rtyper/tool/test/test_rffi_platform.py --- a/rpython/rtyper/tool/test/test_rffi_platform.py +++ b/rpython/rtyper/tool/test/test_rffi_platform.py @@ -277,10 +277,14 @@ assert not rffi_platform.has("x", "#include <some/path/which/cannot/exist>") def test_has_0002(): + if platform.name == 'msvc': + py.test.skip('no m.lib in msvc') assert rffi_platform.has("pow", "#include <math.h>", libraries=["m"]) def test_has_0003(): """multiple libraries""" + if platform.name == 'msvc': + py.test.skip('no m.lib in msvc') assert rffi_platform.has("pow", "#include <math.h>", libraries=["m", "c"]) def test_has_0004(): diff --git a/rpython/translator/c/database.py b/rpython/translator/c/database.py --- a/rpython/translator/c/database.py +++ b/rpython/translator/c/database.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from rpython.rtyper.lltypesystem.lltype import (Primitive, Ptr, typeOf, RuntimeTypeInfo, Struct, Array, FuncType, Void, ContainerType, OpaqueType, @@ -8,9 +9,9 @@ from rpython.rtyper.lltypesystem import llgroup from rpython.tool.sourcetools import valid_identifier from rpython.translator.c.primitive import PrimitiveName, PrimitiveType -from rpython.translator.c.node import StructDefNode, ArrayDefNode -from rpython.translator.c.node import FixedSizeArrayDefNode, BareBoneArrayDefNode -from rpython.translator.c.node import ContainerNodeFactory, ExtTypeOpaqueDefNode +from rpython.translator.c.node import ( + StructDefNode, ArrayDefNode, FixedSizeArrayDefNode, BareBoneArrayDefNode, + ContainerNodeFactory, ExtTypeOpaqueDefNode, FuncNode) from rpython.translator.c.support import cdecl, CNameManager from rpython.translator.c.support import log, barebonearray from rpython.translator.c.extfunc import do_the_getting @@ -28,6 +29,7 @@ def __init__(self, translator=None, standalone=False, gcpolicyclass=None, + exctransformer=None, thread_enabled=False, sandbox=False): self.translator = translator @@ -36,6 +38,7 @@ if gcpolicyclass is None: gcpolicyclass = gc.RefcountingGcPolicy self.gcpolicy = gcpolicyclass(self, thread_enabled) + self.exctransformer = exctransformer self.structdefnodes = {} self.pendingsetupnodes = [] @@ -45,7 +48,7 @@ self.delayedfunctionptrs = [] self.completedcontainers = 0 self.containerstats = {} - self.helper2ptr = {} + self.helpers = OrderedDict() # late_initializations is for when the value you want to # assign to a constant object is something C doesn't think is @@ -53,12 +56,8 @@ self.late_initializations = [] self.namespace = CNameManager() - if translator is None or translator.rtyper is None: - self.exctransformer = None - else: - self.exctransformer = translator.getexceptiontransformer() if translator is not None: - self.gctransformer = self.gcpolicy.gettransformer() + self.gctransformer = self.gcpolicy.gettransformer(translator) self.completed = False self.instrument_ncounter = 0 @@ -348,6 +347,8 @@ assert not self.delayedfunctionptrs self.completed = True + if self.gctransformer is not None and self.gctransformer.inline: + self.gctransformer.inline_helpers(self.all_graphs()) if show_progress: dump() log.database("Completed") @@ -379,30 +380,10 @@ produce(node) return result - def need_sandboxing(self, fnobj): - if not self.sandbox: - return False - if hasattr(fnobj, '_safe_not_sandboxed'): - return not fnobj._safe_not_sandboxed - elif getattr(getattr(fnobj, '_callable', None), - '_sandbox_external_name', None): - return True - else: - return "if_external" - - def prepare_inline_helpers(self): - all_nodes = self.globalcontainers() - funcnodes = [node for node in all_nodes if node.nodekind == 'func'] - graphs = [] - for node in funcnodes: - for graph in node.graphs_to_patch(): - graphs.append(graph) - self.gctransformer.prepare_inline_helpers(graphs) - def all_graphs(self): graphs = [] for node in self.containerlist: - if node.nodekind == 'func': + if isinstance(node, FuncNode): for graph in node.graphs_to_patch(): graphs.append(graph) return graphs diff --git a/rpython/translator/c/external.py b/rpython/translator/c/external.py deleted file mode 100644 --- a/rpython/translator/c/external.py +++ /dev/null @@ -1,54 +0,0 @@ -from rpython.rtyper.lltypesystem.lltype import typeOf, Void -from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring -from rpython.translator.c.support import cdecl, somelettersfrom - -class CExternalFunctionCodeGenerator(object): - if USESLOTS: - __slots__ = """db fnptr FUNCTYPE argtypenames resulttypename""".split() - - def __init__(self, fnptr, db): - self.fnptr = fnptr - self.db = db - self.FUNCTYPE = typeOf(fnptr) - assert Void not in self.FUNCTYPE.ARGS - self.argtypenames = [db.gettype(T) for T in self.FUNCTYPE.ARGS] - self.resulttypename = db.gettype(self.FUNCTYPE.RESULT) - - def graphs_to_patch(self): - return [] - - def name(self, cname): #virtual - return cname - - def argnames(self): - return ['%s%d' % (somelettersfrom(self.argtypenames[i]), i) - for i in range(len(self.argtypenames))] - - def allconstantvalues(self): - return [] - - def implementation_begin(self): - pass - - def cfunction_declarations(self): - if self.FUNCTYPE.RESULT is not Void: - yield '%s;' % cdecl(self.resulttypename, 'result') - - def cfunction_body(self): - try: - convert_params = self.fnptr.convert_params - except AttributeError: - convert_params = lambda backend, args: [arg for _,arg in args] - call = '%s(%s)' % (self.fnptr._name, ', '.join(convert_params("c", zip(self.FUNCTYPE.ARGS, self.argnames())))) - if self.FUNCTYPE.RESULT is not Void: - yield 'result = %s;' % call - yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();' - yield 'return result;' - else: - yield '%s;' % call - yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();' - - def implementation_end(self): - pass - -assert not USESLOTS or '__dict__' not in dir(CExternalFunctionCodeGenerator) diff --git a/rpython/translator/c/extfunc.py b/rpython/translator/c/extfunc.py --- a/rpython/translator/c/extfunc.py +++ b/rpython/translator/c/extfunc.py @@ -1,23 +1,23 @@ import types from rpython.flowspace.model import FunctionGraph -from rpython.rtyper.lltypesystem import lltype, rstr, rlist +from rpython.annotator.listdef import s_list_of_strings +from rpython.rtyper.lltypesystem import lltype, rlist from rpython.rtyper.lltypesystem.rstr import STR, mallocstr from rpython.translator.c.support import cdecl def find_list_of_str(rtyper): - for r in rtyper.reprs.itervalues(): - if isinstance(r, rlist.ListRepr) and r.item_repr is rstr.string_repr: - return r.lowleveltype.TO - return None + r_strlist = rtyper.getrepr(s_list_of_strings) + rtyper.call_all_setups() + return r_strlist.lowleveltype.TO + def predeclare_common_types(db, rtyper): # Common types yield ('RPyString', STR) LIST_OF_STR = find_list_of_str(rtyper) - if LIST_OF_STR is not None: - yield ('RPyListOfString', LIST_OF_STR) + yield ('RPyListOfString', LIST_OF_STR) def predeclare_utility_functions(db, rtyper): # Common utility functions @@ -32,40 +32,38 @@ # returned directly as results LIST_OF_STR = find_list_of_str(rtyper) - if LIST_OF_STR is not None: - p = lltype.Ptr(LIST_OF_STR) + p = lltype.Ptr(LIST_OF_STR) - def _RPyListOfString_New(length=lltype.Signed): - return LIST_OF_STR.ll_newlist(length) + def _RPyListOfString_New(length=lltype.Signed): + return LIST_OF_STR.ll_newlist(length) - def _RPyListOfString_SetItem(l=p, - index=lltype.Signed, - newstring=lltype.Ptr(STR)): - rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring) + def _RPyListOfString_SetItem(l=p, + index=lltype.Signed, + newstring=lltype.Ptr(STR)): + rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring) - def _RPyListOfString_GetItem(l=p, - index=lltype.Signed): - return rlist.ll_getitem_fast(l, index) + def _RPyListOfString_GetItem(l=p, + index=lltype.Signed): + return rlist.ll_getitem_fast(l, index) - def _RPyListOfString_Length(l=p): - return rlist.ll_length(l) + def _RPyListOfString_Length(l=p): + return rlist.ll_length(l) for fname, f in locals().items(): if isinstance(f, types.FunctionType): # XXX this is painful :( - if (LIST_OF_STR, fname) in db.helper2ptr: - yield (fname, db.helper2ptr[LIST_OF_STR, fname]) + if fname in db.helpers: + yield (fname, db.helpers[fname]) else: # hack: the defaults give the type of the arguments graph = rtyper.annotate_helper(f, f.func_defaults) - db.helper2ptr[LIST_OF_STR, fname] = graph + db.helpers[fname] = graph yield (fname, graph) -def predeclare_exception_data(db, rtyper): +def predeclare_exception_data(exctransformer, rtyper): # Exception-related types and constants exceptiondata = rtyper.exceptiondata - exctransformer = db.exctransformer yield ('RPYTHON_EXCEPTION_VTABLE', exceptiondata.lltype_of_exception_type) yield ('RPYTHON_EXCEPTION', exceptiondata.lltype_of_exception_value) @@ -93,19 +91,19 @@ def predeclare_all(db, rtyper): for fn in [predeclare_common_types, predeclare_utility_functions, - predeclare_exception_data, ]: for t in fn(db, rtyper): yield t + exctransformer = db.exctransformer + for t in predeclare_exception_data(exctransformer, rtyper): + yield t + def get_all(db, rtyper): - for fn in [predeclare_common_types, - predeclare_utility_functions, - predeclare_exception_data, - ]: - for t in fn(db, rtyper): - yield t[1] + for name, fnptr in predeclare_all(db, rtyper): + yield fnptr + # ____________________________________________________________ diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py --- a/rpython/translator/c/funcgen.py +++ b/rpython/translator/c/funcgen.py @@ -1,9 +1,8 @@ import sys -from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring from rpython.translator.c.support import cdecl from rpython.translator.c.support import llvalue_from_constant, gen_assignments from rpython.translator.c.support import c_string_constant, barebonearray -from rpython.flowspace.model import Variable, Constant, copygraph +from rpython.flowspace.model import Variable, Constant from rpython.rtyper.lltypesystem.lltype import (Ptr, Void, Bool, Signed, Unsigned, SignedLongLong, Float, UnsignedLongLong, Char, UniChar, ContainerType, Array, FixedSizeArray, ForwardReference, FuncType) @@ -19,39 +18,30 @@ KEEP_INLINED_GRAPHS = False +def make_funcgen(graph, db, exception_policy, functionname): + graph._seen_by_the_backend = True + # apply the exception transformation + if db.exctransformer: + db.exctransformer.create_exception_handling(graph) + # apply the gc transformation + if db.gctransformer: + db.gctransformer.transform_graph(graph) + return FunctionCodeGenerator(graph, db, exception_policy, functionname) + class FunctionCodeGenerator(object): """ Collects information about a function which we have to generate from a flow graph. """ - if USESLOTS: - __slots__ = """graph db gcpolicy - exception_policy - more_ll_values - vars all_cached_consts - illtypes - functionname - blocknum - innerloops - oldgraph""".split() - - def __init__(self, graph, db, exception_policy=None, functionname=None): - graph._seen_by_the_backend = True + def __init__(self, graph, db, exception_policy, functionname): self.graph = graph self.db = db self.gcpolicy = db.gcpolicy self.exception_policy = exception_policy self.functionname = functionname - # apply the exception transformation - if self.db.exctransformer: - self.db.exctransformer.create_exception_handling(self.graph) - # apply the gc transformation - if self.db.gctransformer: - self.db.gctransformer.transform_graph(self.graph) - #self.graph.show() + self.collect_var_and_types() - for v in self.vars: T = v.concretetype # obscure: skip forward references and hope for the best @@ -84,12 +74,6 @@ self.more_ll_values.append(link.llexitcase) elif link.exitcase is not None: mix.append(Constant(link.exitcase)) - if self.exception_policy == "CPython": - v, exc_cleanup_ops = self.graph.exc_cleanup - mix.append(v) - for cleanupop in exc_cleanup_ops: - mix.extend(cleanupop.args) - mix.append(cleanupop.result) uniquemix = [] seen = identity_dict() @@ -99,20 +83,7 @@ seen[v] = True self.vars = uniquemix - def name(self, cname): #virtual - return cname - - def patch_graph(self, copy_graph): - graph = self.graph - if self.db.gctransformer and self.db.gctransformer.inline: - if copy_graph: - graph = copygraph(graph, shallow=True) - self.db.gctransformer.inline_helpers(graph) - return graph - def implementation_begin(self): - self.oldgraph = self.graph - self.graph = self.patch_graph(copy_graph=True) SSI_to_SSA(self.graph) self.collect_var_and_types() self.blocknum = {} @@ -138,8 +109,6 @@ self.vars = None self.blocknum = None self.innerloops = None - self.graph = self.oldgraph - del self.oldgraph def argnames(self): return [LOCALVAR % v.name for v in self.graph.getargs()] @@ -247,8 +216,6 @@ yield '}' link = block.exits[0] assert link.exitcase in (False, True) - #yield 'assert(%s == %s);' % (self.expr(block.exitswitch), - # self.genc.nameofvalue(link.exitcase, ct)) for op in self.gen_link(link): yield op elif TYPE in (Signed, Unsigned, SignedLongLong, @@ -894,14 +861,11 @@ def getdebugfunctionname(self): name = self.functionname - if not name: - return "?" if name.startswith('pypy_g_'): name = name[7:] return name def OP_DEBUG_RECORD_TRACEBACK(self, op): - #if self.functionname is None, we print "?" as the argument */ return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % ( self.getdebugfunctionname(),) @@ -941,5 +905,3 @@ cdecl(typename, ''), self.expr(op.args[0]), self.expr(op.result)) - -assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator) diff --git a/rpython/translator/c/gc.py b/rpython/translator/c/gc.py --- a/rpython/translator/c/gc.py +++ b/rpython/translator/c/gc.py @@ -1,8 +1,7 @@ import sys from rpython.flowspace.model import Constant -from rpython.rtyper.lltypesystem import lltype -from rpython.rtyper.lltypesystem.lltype import (typeOf, RttiStruct, - RuntimeTypeInfo, top_container) +from rpython.rtyper.lltypesystem.lltype import (RttiStruct, + RuntimeTypeInfo) from rpython.translator.c.node import ContainerNode from rpython.translator.c.support import cdecl from rpython.translator.tool.cbuild import ExternalCompilationInfo @@ -18,23 +17,12 @@ return defnode.db.gctransformer.HDR return None - def common_gcheader_initdata(self, defnode): - if defnode.db.gctransformer is not None: - raise NotImplementedError - return None - def struct_gcheader_definition(self, defnode): return self.common_gcheader_definition(defnode) - def struct_gcheader_initdata(self, defnode): - return self.common_gcheader_initdata(defnode) - def array_gcheader_definition(self, defnode): return self.common_gcheader_definition(defnode) - def array_gcheader_initdata(self, defnode): - return self.common_gcheader_initdata(defnode) - def compilation_info(self): if not self.db: return ExternalCompilationInfo() @@ -46,9 +34,6 @@ ] ) - def get_prebuilt_hash(self, obj): - return None - def need_no_typeptr(self): return False @@ -109,16 +94,9 @@ class RefcountingGcPolicy(BasicGcPolicy): - def gettransformer(self): + def gettransformer(self, translator): from rpython.memory.gctransform import refcounting - return refcounting.RefcountingGCTransformer(self.db.translator) - - def common_gcheader_initdata(self, defnode): - if defnode.db.gctransformer is not None: - gct = defnode.db.gctransformer - top = top_container(defnode.obj) - return gct.gcheaderbuilder.header_of_object(top)._obj - return None + return refcounting.RefcountingGCTransformer(translator) # for structs @@ -197,16 +175,9 @@ class BoehmGcPolicy(BasicGcPolicy): - def gettransformer(self): + def gettransformer(self, translator): from rpython.memory.gctransform import boehm - return boehm.BoehmGCTransformer(self.db.translator) - - def common_gcheader_initdata(self, defnode): - if defnode.db.gctransformer is not None: - hdr = lltype.malloc(defnode.db.gctransformer.HDR, immortal=True) - hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr()) - return hdr._obj - return None + return boehm.BoehmGCTransformer(translator) def array_setup(self, arraydefnode): pass @@ -313,9 +284,9 @@ class BasicFrameworkGcPolicy(BasicGcPolicy): - def gettransformer(self): + def gettransformer(self, translator): if hasattr(self, 'transformerclass'): # for rpython/memory tests - return self.transformerclass(self.db.translator) + return self.transformerclass(translator) raise NotImplementedError def struct_setup(self, structdefnode, rtti): @@ -362,24 +333,6 @@ args = [funcgen.expr(v) for v in op.args] return '%s = %s; /* for moving GCs */' % (args[1], args[0]) - def common_gcheader_initdata(self, defnode): - o = top_container(defnode.obj) - needs_hash = self.get_prebuilt_hash(o) is not None - hdr = defnode.db.gctransformer.gc_header_for(o, needs_hash) - return hdr._obj - - def get_prebuilt_hash(self, obj): - # for prebuilt objects that need to have their hash stored and - # restored. Note that only structures that are StructNodes all - # the way have their hash stored (and not e.g. structs with var- - # sized arrays at the end). 'obj' must be the top_container. - TYPE = typeOf(obj) - if not isinstance(TYPE, lltype.GcStruct): - return None - if TYPE._is_varsize(): - return None - return getattr(obj, '_hash_cache_', None) - def need_no_typeptr(self): config = self.db.translator.config return config.translation.gcremovetypeptr @@ -440,15 +393,15 @@ class ShadowStackFrameworkGcPolicy(BasicFrameworkGcPolicy): - def gettransformer(self): + def gettransformer(self, translator): from rpython.memory.gctransform import shadowstack - return shadowstack.ShadowStackFrameworkGCTransformer(self.db.translator) + return shadowstack.ShadowStackFrameworkGCTransformer(translator) class AsmGcRootFrameworkGcPolicy(BasicFrameworkGcPolicy): - def gettransformer(self): + def gettransformer(self, translator): from rpython.memory.gctransform import asmgcroot - return asmgcroot.AsmGcRootFrameworkGCTransformer(self.db.translator) + return asmgcroot.AsmGcRootFrameworkGCTransformer(translator) def GC_KEEPALIVE(self, funcgen, v): return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -126,8 +126,10 @@ if not self.standalone: raise NotImplementedError("--gcrootfinder=asmgcc requires standalone") + exctransformer = translator.getexceptiontransformer() db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, + exctransformer=exctransformer, thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db @@ -193,22 +195,8 @@ DEBUG_DEFINES = {'RPY_ASSERT': 1, 'RPY_LL_ASSERT': 1} - def generate_graphs_for_llinterp(self, db=None): - # prepare the graphs as when the source is generated, but without - # actually generating the source. - if db is None: - db = self.build_database() - graphs = db.all_graphs() - db.gctransformer.prepare_inline_helpers(graphs) - for node in db.containerlist: - if hasattr(node, 'funcgens'): - for funcgen in node.funcgens: - funcgen.patch_graph(copy_graph=False) - return db - def generate_source(self, db=None, defines={}, exe_name=None): assert self.c_source_filename is None - if db is None: db = self.build_database() pf = self.getentrypointptr() @@ -846,7 +834,6 @@ # sg = SourceGenerator(database) sg.set_strategy(targetdir, split) - database.prepare_inline_helpers() sg.gen_readable_parts_of_source(f) headers_to_precompile = sg.headers_to_precompile[:] headers_to_precompile.insert(0, incfilename) diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py --- a/rpython/translator/c/node.py +++ b/rpython/translator/c/node.py @@ -3,8 +3,7 @@ Void, OpaqueType, Float, RuntimeTypeInfo, getRuntimeTypeInfo, Char, _subarray) from rpython.rtyper.lltypesystem import llmemory, llgroup -from rpython.translator.c.funcgen import FunctionCodeGenerator -from rpython.translator.c.external import CExternalFunctionCodeGenerator +from rpython.translator.c.funcgen import make_funcgen from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring from rpython.translator.c.support import cdecl, forward_cdecl, somelettersfrom from rpython.translator.c.support import c_char_array_constant, barebonearray @@ -540,7 +539,17 @@ class StructNode(ContainerNode): nodekind = 'struct' if USESLOTS: - __slots__ = () + __slots__ = ('gc_init',) + + def __init__(self, db, T, obj): + ContainerNode.__init__(self, db, T, obj) + if needs_gcheader(T): + gct = self.db.gctransformer + if gct is not None: + self.gc_init = gct.gcheader_initdata(self) + db.getcontainernode(self.gc_init) + else: + self.gc_init = None def basename(self): T = self.getTYPE() @@ -567,8 +576,7 @@ data = [] if needs_gcheader(T): - gc_init = self.db.gcpolicy.struct_gcheader_initdata(self) - data.append(('gcheader', gc_init)) + data.append(('gcheader', self.gc_init)) for name in defnode.fieldnames: data.append((name, getattr(self.obj, name))) @@ -641,7 +649,7 @@ def implementation(self): hash_typename = self.get_hash_typename() - hash = self.db.gcpolicy.get_prebuilt_hash(self.obj) + hash = self.db.gctransformer.get_prebuilt_hash(self.obj) assert hash is not None lines = list(self.initializationexpr()) lines.insert(0, '%s = { {' % ( @@ -651,7 +659,8 @@ return lines def gcstructnode_factory(db, T, obj): - if db.gcpolicy.get_prebuilt_hash(obj) is not None: + if (db.gctransformer and + db.gctransformer.get_prebuilt_hash(obj) is not None): cls = GcStructNodeWithHash else: cls = StructNode @@ -661,7 +670,17 @@ class ArrayNode(ContainerNode): nodekind = 'array' if USESLOTS: - __slots__ = () + __slots__ = ('gc_init',) + + def __init__(self, db, T, obj): + ContainerNode.__init__(self, db, T, obj) + if needs_gcheader(T): + gct = self.db.gctransformer + if gct is not None: + self.gc_init = gct.gcheader_initdata(self) + db.getcontainernode(self.gc_init) + else: + self.gc_init = None def getptrname(self): if barebonearray(self.getTYPE()): @@ -681,8 +700,7 @@ T = self.getTYPE() yield '{' if needs_gcheader(T): - gc_init = self.db.gcpolicy.array_gcheader_initdata(self) - lines = generic_initializationexpr(self.db, gc_init, 'gcheader', + lines = generic_initializationexpr(self.db, self.gc_init, 'gcheader', '%sgcheader' % (decoration,)) for line in lines: yield line @@ -781,81 +799,64 @@ comma = '' expr += comma i = expr.find('\n') - if i<0: i = len(expr) + if i < 0: + i = len(expr) expr = '%s\t/* %s */%s' % (expr[:i], decoration, expr[i:]) return expr.split('\n') # ____________________________________________________________ -class FuncNode(ContainerNode): +class FuncNodeBase(ContainerNode): nodekind = 'func' eci_name = 'compilation_info' # there not so many node of this kind, slots should not # be necessary - - def __init__(self, db, T, obj, forcename=None): + def __init__(self, db, T, obj, ptrname): Node.__init__(self, db) self.globalcontainer = True self.T = T self.obj = obj - callable = getattr(obj, '_callable', None) - if (callable is not None and - getattr(callable, 'c_name', None) is not None): - self.name = forcename or obj._callable.c_name - elif getattr(obj, 'external', None) == 'C' and not db.need_sandboxing(obj): - self.name = forcename or self.basename() - else: - self.name = (forcename or - db.namespace.uniquename('g_' + self.basename())) - self.make_funcgens() + self.name = ptrname self.typename = db.gettype(T) #, who_asks=self) def getptrname(self): return self.name - def make_funcgens(self): - self.funcgens = select_function_code_generators(self.obj, self.db, self.name) - if self.funcgens: - argnames = self.funcgens[0].argnames() #Assume identical for all funcgens - self.implementationtypename = self.db.gettype(self.T, argnames=argnames) - self._funccodegen_owner = self.funcgens[0] - else: - self._funccodegen_owner = None - def basename(self): return self.obj._name + +class FuncNode(FuncNodeBase): + def __init__(self, db, T, obj, ptrname): + FuncNodeBase.__init__(self, db, T, obj, ptrname) + exception_policy = getattr(obj, 'exception_policy', None) + self.funcgen = make_funcgen(obj.graph, db, exception_policy, ptrname) + argnames = self.funcgen.argnames() + self.implementationtypename = db.gettype(T, argnames=argnames) + self._funccodegen_owner = self.funcgen + def enum_dependencies(self): - if not self.funcgens: - return [] - return self.funcgens[0].allconstantvalues() #Assume identical for all funcgens + return self.funcgen.allconstantvalues() def forward_declaration(self): callable = getattr(self.obj, '_callable', None) is_exported = getattr(callable, 'exported_symbol', False) - for funcgen in self.funcgens: - yield '%s;' % ( - forward_cdecl(self.implementationtypename, - funcgen.name(self.name), self.db.standalone, - is_exported=is_exported)) + yield '%s;' % ( + forward_cdecl(self.implementationtypename, + self.name, self.db.standalone, is_exported=is_exported)) + + def graphs_to_patch(self): + for i in self.funcgen.graphs_to_patch(): + yield i def implementation(self): - for funcgen in self.funcgens: - for s in self.funcgen_implementation(funcgen): - yield s - - def graphs_to_patch(self): - for funcgen in self.funcgens: - for i in funcgen.graphs_to_patch(): - yield i - - def funcgen_implementation(self, funcgen): + funcgen = self.funcgen funcgen.implementation_begin() # recompute implementationtypename as the argnames may have changed argnames = funcgen.argnames() implementationtypename = self.db.gettype(self.T, argnames=argnames) - yield '%s {' % cdecl(implementationtypename, funcgen.name(self.name)) + yield '%s {' % cdecl(implementationtypename, self.name) # # declare the local variables # @@ -866,7 +867,7 @@ while start < len(localnames): # pack the local declarations over as few lines as possible total = lengths[start] + 8 - end = start+1 + end = start + 1 while total + lengths[end] < 77: total += lengths[end] + 1 end += 1 @@ -897,44 +898,55 @@ del bodyiter funcgen.implementation_end() -def sandbox_stub(fnobj, db): - # unexpected external function for --sandbox translation: replace it - # with a "Not Implemented" stub. To support these functions, port them - # to the new style registry (e.g. rpython.module.ll_os.RegisterOs). - from rpython.translator.sandbox import rsandbox - graph = rsandbox.get_external_function_sandbox_graph(fnobj, db, - force_stub=True) - return [FunctionCodeGenerator(graph, db)] +class ExternalFuncNode(FuncNodeBase): + def __init__(self, db, T, obj, ptrname): + FuncNodeBase.__init__(self, db, T, obj, ptrname) + self._funccodegen_owner = None -def sandbox_transform(fnobj, db): - # for --sandbox: replace a function like os_open_llimpl() with - # code that communicates with the external process to ask it to - # perform the operation. - from rpython.translator.sandbox import rsandbox - graph = rsandbox.get_external_function_sandbox_graph(fnobj, db) - return [FunctionCodeGenerator(graph, db)] + def enum_dependencies(self): + return [] -def select_function_code_generators(fnobj, db, functionname): - sandbox = db.need_sandboxing(fnobj) - if hasattr(fnobj, 'graph'): - if sandbox and sandbox != "if_external": - # apply the sandbox transformation - return sandbox_transform(fnobj, db) - exception_policy = getattr(fnobj, 'exception_policy', None) - return [FunctionCodeGenerator(fnobj.graph, db, exception_policy, - functionname)] - elif getattr(fnobj, 'external', None) is not None: - if sandbox: - return sandbox_stub(fnobj, db) - elif fnobj.external == 'C': - return [] - else: - assert fnobj.external == 'CPython' - return [CExternalFunctionCodeGenerator(fnobj, db)] - elif hasattr(fnobj._callable, "c_name"): - return [] # this case should only be used for entrypoints + def forward_declaration(self): + return [] + + def implementation(self): + return [] + +def new_funcnode(db, T, obj, forcename=None): + if db.sandbox: + if (getattr(obj, 'external', None) is not None and + not obj._safe_not_sandboxed): + from rpython.translator.sandbox import rsandbox + obj.__dict__['graph'] = rsandbox.get_sandbox_stub( + obj, db.translator.rtyper) + obj.__dict__.pop('_safe_not_sandboxed', None) + obj.__dict__.pop('external', None) + if forcename: + name = forcename else: - raise ValueError("don't know how to generate code for %r" % (fnobj,)) + name = _select_name(db, obj) + if hasattr(obj, 'graph'): + return FuncNode(db, T, obj, name) + elif getattr(obj, 'external', None) is not None: + assert obj.external == 'C' + if db.sandbox: + assert obj._safe_not_sandboxed + return ExternalFuncNode(db, T, obj, name) + elif hasattr(obj._callable, "c_name"): + return ExternalFuncNode(db, T, obj, name) # this case should only be used for entrypoints + else: + raise ValueError("don't know how to generate code for %r" % (obj,)) + + +def _select_name(db, obj): + try: + return obj._callable.c_name + except AttributeError: + pass + if getattr(obj, 'external', None) == 'C': + return obj._name + return db.namespace.uniquename('g_' + obj._name) + class ExtType_OpaqueNode(ContainerNode): nodekind = 'rpyopaque' @@ -1044,7 +1056,7 @@ Array: ArrayNode, GcArray: ArrayNode, FixedSizeArray: FixedSizeArrayNode, - FuncType: FuncNode, + FuncType: new_funcnode, OpaqueType: opaquenode_factory, llmemory._WeakRefType: weakrefnode_factory, llgroup.GroupType: GroupNode, diff --git a/rpython/translator/c/test/test_database.py b/rpython/translator/c/test/test_database.py --- a/rpython/translator/c/test/test_database.py +++ b/rpython/translator/c/test/test_database.py @@ -9,8 +9,6 @@ def dump_on_stdout(database): - if database.gctransformer: - database.prepare_inline_helpers() print '/*********************************/' structdeflist = database.getstructdeflist() for node in structdeflist: @@ -171,7 +169,7 @@ F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) - db = LowLevelDatabase(t) + db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer()) db.get(f) db.complete() dump_on_stdout(db) @@ -186,7 +184,7 @@ return p.x * p.y t, graph = makegraph(ll_f, [int]) - db = LowLevelDatabase(t) + db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer()) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db) @@ -207,7 +205,7 @@ return s.ptr1.x * s.ptr2.x t, graph = makegraph(ll_f, [int]) - db = LowLevelDatabase(t) + db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer()) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db) diff --git a/rpython/translator/c/test/test_refcount.py b/rpython/translator/c/test/test_refcount.py --- a/rpython/translator/c/test/test_refcount.py +++ b/rpython/translator/c/test/test_refcount.py @@ -106,37 +106,6 @@ assert fn(1) == 4 assert fn(0) == 5 - def test_del_basic(self): - py.test.skip("xxx fix or kill") - S = lltype.GcStruct('S', ('x', lltype.Signed), rtti=True) - TRASH = lltype.GcStruct('TRASH', ('x', lltype.Signed)) - GLOBAL = lltype.Struct('GLOBAL', ('x', lltype.Signed)) - glob = lltype.malloc(GLOBAL, immortal=True) - def destructor(s): - glob.x = s.x + 1 - def type_info_S(s): - return lltype.getRuntimeTypeInfo(S) - - def g(n): - s = lltype.malloc(S) - s.x = n - # now 's' should go away - def entrypoint(n): - g(n) - # llop.gc__collect(lltype.Void) - return glob.x - - t = TranslationContext() - t.buildannotator().build_types(entrypoint, [int]) - rtyper = t.buildrtyper() - destrptr = rtyper.annotate_helper_fn(destructor, [lltype.Ptr(S)]) - rtyper.attachRuntimeTypeInfoFunc(S, type_info_S, destrptr=destrptr) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit