From mwh at codespeak.net Wed Mar 1 00:50:35 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 1 Mar 2006 00:50:35 +0100 (CET) Subject: [pypy-svn] r23795 - pypy/dist/pypy/module/stackless/test Message-ID: <20060228235035.19C1F1008B@code0.codespeak.net> Author: mwh Date: Wed Mar 1 00:50:32 2006 New Revision: 23795 Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Log: (moshez, mwh) Add a not-run test that uses coroutines to compare the preorder traversal of two trees (and is named to suggest it does something else entirely) Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py (original) +++ pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Wed Mar 1 00:50:32 2006 @@ -209,3 +209,96 @@ data = wrap_stackless_function(f) assert int(data.strip()) == 4711 + +def dont_test_tree_differ(): + class Node: + def __init__(self, value, left=None, right=None): + self.value = value + self.left = left + self.right = right + def __repr__(self): + return 'Node(%r, %r, %r)'%(self.value, self.left, self.right) + + tree1 = Node(1, Node(2)) + tree2 = Node(1, Node(2)) + + def eq(t1, t2): + if t1 is None: + return t2 is None + if t1.value != t2.value: + return False + if t1.left is None: + if t2.left is None: + return eq(t1.right, t2.right) + else: + return False + if t2.right is None: + if t1.right is None: + return eq(t1.left, t2.left) + else: + return False + else: + return eq(t1.left, t2.left) and eq(t1.right, t2.right) + +# assert not eq(tree1, tree2) + + class Super: + pass + class Producer(Super): + def __init__(self, tree, objects, consumer): + self.tree = tree + self.objects = objects + self.consumer = consumer + def produce(self, t): + if t is None: + return + self.objects.append(t.value) + self.consumer.switch() + self.produce(t.left) + self.produce(t.right) + def call(self): + self.produce(self.tree) + while 1: + self.consumer.switch() + class Consumer(Super): + def __init__(self, tree, objects, producer): + self.tree = tree + self.objects = objects + self.producer = producer + def consume(self, t): + if t is None: + return True + self.producer.switch() + if not self.objects: + return False + if self.objects.pop(0) != t.value: + return False + if not self.consume(t.left): + return False + return self.consume(t.right) + + def call(self): + self.result = self.consume(self.tree) + costate.main.switch() + + def eq2(t1, t2): + objects = [] + producer = Coroutine() + consumer = Coroutine() + + producer.bind(Producer(t1, objects, consumer)) + cons = Consumer(t2, objects, producer) + consumer.bind(cons) + + consumer.switch() + + return cons.result + + def ep(): + return eq2(tree1, tree2) + + output = wrap_stackless_function(ep) + print '!!!!!!', output + assert False + + From mwh at codespeak.net Wed Mar 1 01:27:54 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 1 Mar 2006 01:27:54 +0100 (CET) Subject: [pypy-svn] r23796 - pypy/dist/pypy/module/stackless/test Message-ID: <20060301002754.6D7591007F@code0.codespeak.net> Author: mwh Date: Wed Mar 1 01:27:51 2006 New Revision: 23796 Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Log: (moshez, mwh) clean up our test a bit, rename some things to be less actively misleading, test a bit more. oh, and actually run the test. Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py (original) +++ pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Wed Mar 1 01:27:51 2006 @@ -210,7 +210,7 @@ data = wrap_stackless_function(f) assert int(data.strip()) == 4711 -def dont_test_tree_differ(): +def test_tree_compare(): class Node: def __init__(self, value, left=None, right=None): self.value = value @@ -219,29 +219,10 @@ def __repr__(self): return 'Node(%r, %r, %r)'%(self.value, self.left, self.right) - tree1 = Node(1, Node(2)) - tree2 = Node(1, Node(2)) + tree1 = Node(1, Node(2, Node(3))) + tree2 = Node(1, Node(3, Node(2))) + tree3 = Node(1, Node(2), Node(3)) - def eq(t1, t2): - if t1 is None: - return t2 is None - if t1.value != t2.value: - return False - if t1.left is None: - if t2.left is None: - return eq(t1.right, t2.right) - else: - return False - if t2.right is None: - if t1.right is None: - return eq(t1.left, t2.left) - else: - return False - else: - return eq(t1.left, t2.left) and eq(t1.right, t2.right) - -# assert not eq(tree1, tree2) - class Super: pass class Producer(Super): @@ -281,7 +262,7 @@ self.result = self.consume(self.tree) costate.main.switch() - def eq2(t1, t2): + def pre_order_eq(t1, t2): objects = [] producer = Coroutine() consumer = Coroutine() @@ -295,10 +276,14 @@ return cons.result def ep(): - return eq2(tree1, tree2) + return "%d %d %d %d"%(pre_order_eq(tree1, tree2), + pre_order_eq(tree1, tree1), + pre_order_eq(tree1, tree3), + pre_order_eq(tree2, tree1), + ) + output = wrap_stackless_function(ep) - print '!!!!!!', output - assert False + assert output.strip() == '0 1 1 0' From rxe at codespeak.net Wed Mar 1 01:32:02 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 01:32:02 +0100 (CET) Subject: [pypy-svn] r23798 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060301003202.191331007F@code0.codespeak.net> Author: rxe Date: Wed Mar 1 01:31:52 2006 New Revision: 23798 Added: pypy/dist/pypy/translator/llvm/pyllvm/autopath.py (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.c pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.s pypy/dist/pypy/translator/llvm/pyllvm/test/hello.c pypy/dist/pypy/translator/llvm/pyllvm/test/hello.s Removed: pypy/dist/pypy/translator/llvm/pyllvm/hello.c pypy/dist/pypy/translator/llvm/pyllvm/hello.s Modified: pypy/dist/pypy/translator/llvm/pyllvm/ (props changed) pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp pypy/dist/pypy/translator/llvm/pyllvm/setup.py pypy/dist/pypy/translator/llvm/pyllvm/test/ (props changed) pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Rationalise the build and use py.test. With some serious crossing of fingers, one should be able to do $ python setup.py build_ext -i $ py.test Added: pypy/dist/pypy/translator/llvm/pyllvm/autopath.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/autopath.py Wed Mar 1 01:31:52 2006 @@ -0,0 +1,120 @@ +""" +self cloning, automatic path configuration + +copy this into any subdirectory of pypy from which scripts need +to be run, typically all of the test subdirs. +The idea is that any such script simply issues + + import autopath + +and this will make sure that the parent directory containing "pypy" +is in sys.path. + +If you modify the master "autopath.py" version (in pypy/tool/autopath.py) +you can directly run it which will copy itself on all autopath.py files +it finds under the pypy root directory. + +This module always provides these attributes: + + pypydir pypy root directory path + this_dir directory where this autopath.py resides + +""" + + +def __dirinfo(part): + """ return (partdir, this_dir) and insert parent of partdir + into sys.path. If the parent directories don't have the part + an EnvironmentError is raised.""" + + import sys, os + try: + head = this_dir = os.path.realpath(os.path.dirname(__file__)) + except NameError: + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) + + while head: + partdir = head + head, tail = os.path.split(head) + if tail == part: + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + fullorig = os.path.join(os.path.realpath(orig), '') + if fullorig.startswith(pypy_root): + if os.path.exists(os.path.join(fullorig, '__init__.py')): + sys.path.remove(orig) + try: + sys.path.remove(head) + except ValueError: + pass + sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + + return partdir, this_dir + +def __clone(): + """ clone master version of autopath.py into all subdirs """ + from os.path import join, walk + if not this_dir.endswith(join('pypy','tool')): + raise EnvironmentError("can only clone master version " + "'%s'" % join(pypydir, 'tool',_myname)) + + + def sync_walker(arg, dirname, fnames): + if _myname in fnames: + fn = join(dirname, _myname) + f = open(fn, 'rwb+') + try: + if f.read() == arg: + print "checkok", fn + else: + print "syncing", fn + f = open(fn, 'w') + f.write(arg) + finally: + f.close() + s = open(join(pypydir, 'tool', _myname), 'rb').read() + walk(pypydir, sync_walker, s) + +_myname = 'autopath.py' + +# set guaranteed attributes + +pypydir, this_dir = __dirinfo('pypy') + +if __name__ == '__main__': + __clone() Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Wed Mar 1 01:31:52 2006 @@ -12,6 +12,7 @@ #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/DerivedTypes.h" // c++ includes #include @@ -19,32 +20,202 @@ using namespace llvm; -static PyObject *pyllvm_start_ee(PyObject *self, PyObject *args) { - char *modulename, *llcode; +typedef struct { + PyObject_HEAD + ExecutionEngine *exec; - if (!PyArg_ParseTuple(args, "ss", &modulename, &llcode)) { +} PyExecutionEngine; + + +static PyObject *ee_parse(PyExecutionEngine *self, PyObject *args) { + char *llcode; + + if (!PyArg_ParseTuple(args, "s", &llcode)) { return NULL; } try { - Module *mod = new Module((const char *) modulename); + ParseAssemblyString((const char *) llcode, &self->exec->getModule()); + verifyModule(self->exec->getModule(), ThrowExceptionAction); + Py_INCREF(Py_None); + return Py_None; + + } catch (const ParseException &ref) { + PyErr_SetString(PyExc_Exception, ref.getMessage().c_str()); + + } catch (...) { + PyErr_SetString(PyExc_Exception, "Unexpected unknown exception occurred"); + } + + return NULL; +} + +static PyObject *ee_call_noargs(PyExecutionEngine *self, PyObject *args) { + + char *fnname; + + if (!PyArg_ParseTuple(args, "s", &fnname)) { + return NULL; + } + + try { + Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname)); + if (fn == NULL) { + PyErr_SetString(PyExc_Exception, "Failed to resolve function"); + return NULL; + } + + if (!fn->arg_empty()) { + PyErr_SetString(PyExc_Exception, "Resolved function must take no args"); + return NULL; + } + + std::vector noargs(0); + GenericValue ret = self->exec->runFunction(fn, noargs); + + } catch (...) { + PyErr_SetString(PyExc_Exception, "Unexpected unknown exception occurred"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *ee_functions(PyExecutionEngine *self, PyObject *args) { + + Module::FunctionListType &fns = self->exec->getModule().getFunctionList(); + for (Module::FunctionListType::const_iterator ii = fns.begin(); ii != fns.end(); ++ii) { + if (ii->isIntrinsic() || ii->isExternal()) { + continue; + } + std::cout << ii->getReturnType()->getDescription() << " " << ii->getName() << std::endl; + std::cout << " -> " << ii->getFunctionType()->getDescription() << std::endl; + std::cout << std::endl; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef ee_methodlist[] = { + {"parse", (PyCFunction) ee_parse, METH_VARARGS, NULL}, + {"functions", (PyCFunction) ee_functions, METH_NOARGS, NULL}, + {"call_noargs", (PyCFunction) ee_call_noargs, METH_VARARGS, NULL}, + + {NULL, NULL} +}; + +void ee_dealloc(PyExecutionEngine *self); +PyObject *ee_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +// PyTypeObject - pythons type structure +PyTypeObject ExecutionEngine_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "ExecutionEngine", + sizeof(PyExecutionEngine), + 0, + (destructor)ee_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ee_methodlist, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +PyObject *pyllvm_execution_engine; + +static PyObject *ee_factory() { + + if (pyllvm_execution_engine != NULL) { + PyErr_SetString(PyExc_Exception, "This should not happen"); + return NULL; + } + + ExecutionEngine *exec; + + try { + Module *mod = new Module((const char *) "my module"); ModuleProvider *mp = new ExistingModuleProvider(mod); - ParseAssemblyString((const char *) llcode, mod);// throw (ParseException) - verifyModule(*mod, ThrowExceptionAction); - ExecutionEngine *exec = ExecutionEngine::create(mp, false); + exec = ExecutionEngine::create(mp, false); assert(exec && "Couldn't create an ExecutionEngine, not even an interpreter?"); - delete exec; } catch (...) { PyErr_SetString(PyExc_Exception, "Unexpected unknown exception occurred"); return NULL; } + PyTypeObject *type = &ExecutionEngine_Type; + + PyExecutionEngine *self = (PyExecutionEngine *) type->tp_alloc(type, 0); + self->exec = exec; + + return (PyObject *) self; +} + +void ee_dealloc(PyExecutionEngine *self) { + // next and prev taken care of by append/remove/dealloc in dlist + self->ob_type->tp_free((PyObject*) self); +} + +static PyObject *pyllvm_get_ee(PyObject *self, PyObject *args) { + if (pyllvm_execution_engine != NULL) { + Py_INCREF(pyllvm_execution_engine); + return pyllvm_execution_engine; + } + + pyllvm_execution_engine = ee_factory(); + return pyllvm_execution_engine; +} + +static PyObject *pyllvm_delete_ee(PyObject *self, PyObject *args) { + PyExecutionEngine *ee = (PyExecutionEngine *) pyllvm_execution_engine; + if (ee != NULL) { + + // bye + if (ee->exec != NULL) { + delete ee->exec; + } + + Py_DECREF(pyllvm_execution_engine); + pyllvm_execution_engine = NULL; + } + Py_INCREF(Py_None); return Py_None; } PyMethodDef pyllvm_functions[] = { - {"start_ee", pyllvm_start_ee, METH_VARARGS, NULL}, + {"get_ee", pyllvm_get_ee, METH_NOARGS, NULL}, + {"delete_ee", pyllvm_delete_ee, METH_NOARGS, NULL}, {NULL, NULL} }; @@ -54,7 +225,15 @@ #endif void initpyllvm(void) { - Py_InitModule("pyllvm", pyllvm_functions); + PyObject *module = Py_InitModule("pyllvm", pyllvm_functions); + + if(PyType_Ready(&ExecutionEngine_Type) < 0) { + return; + } + + Py_INCREF(&ExecutionEngine_Type); + PyModule_AddObject(module, "ExecutionEngine", + (PyObject*) &ExecutionEngine_Type); } Modified: pypy/dist/pypy/translator/llvm/pyllvm/setup.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/setup.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/setup.py Wed Mar 1 01:31:52 2006 @@ -1,9 +1,17 @@ +import autopath +import py + from distutils.core import setup from distutils.extension import Extension + import os import glob -sources = ['pyllvm.cpp'] +# XXX make libdir configurable +#libdir = py.path.local("/usr/local/lib/") +libdir = py.path.local(__file__).dirpath().join("libs") + +# get all the extra objects llvm needs extra_objects = """ LLVMX86.o LLVMSystem.o @@ -29,21 +37,37 @@ LLVMBCReader.o """.split() -unused = """ +# globals +name = 'pyllvm' +sources = ['pyllvm.cpp'] +libraries = ["LLVMTarget"] +include_dirs = ['/opt/projects/llvm-1.6/build/include'] +library_dirs = [str(libdir)] +define_macros = [('_GNU_SOURCE', None), ('__STDC_LIMIT_MACROS', None)] +extra_objects = [str(libdir.join(obj)) for obj in extra_objects] + +opts = dict(name=name, + sources=sources, + libraries=libraries, + include_dirs=include_dirs, + library_dirs=library_dirs, + define_macros=define_macros, + extra_objects=extra_objects) + +ext_modules = Extension(**opts) + +# setup module +setup(name=name, ext_modules=[ext_modules]) + +# bunch of unused object (at the moment or for x86) +unused_objects = """ LLVMSkeleton.o LLVMProfilePaths.o - LLVMCBackend.o - LLVMDebugger.o - - profile_rt.o trace.o gcsemispace.o - - - LLVMSparcV8.o LLVMSparcV9.o LLVMSparcV9InstrSched.o @@ -56,27 +80,5 @@ sample.o stkr_compiler.o LLVMTarget.o - """ -extra_objects = ["/usr/local/lib/" + name for name in extra_objects] - -libs = ["LLVMTarget"] -#for fn in glob.glob("/usr/local/lib/*.a"): -# fn = os.path.basename(fn) -# if 'LLVM' in fn: -# libs.append(os.path.splitext(fn[len("lib"):])[0]) - -includes = ['/opt/projects/llvm-1.6/build/include'] -defs = [('_GNU_SOURCE', None), - ('__STDC_LIMIT_MACROS', None), - ] - -setup(name = 'pyllvm', - version = '0.0', - ext_modules = [Extension(name = 'pyllvm', - define_macros=defs, - sources = sources, - include_dirs = includes, - libraries = libs, - extra_objects = extra_objects)]) Added: pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.c ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.c Wed Mar 1 01:31:52 2006 @@ -0,0 +1,4 @@ +int add(int n, int y) { + return n + y; +} + Added: pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.s ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/addnumbers.s Wed Mar 1 01:31:52 2006 @@ -0,0 +1,441 @@ +; GNU C version 3.4-llvm 20051104 (LLVM 1.6) (i686-pc-linux-gnu) +; compiled by GNU C version 3.4.0. +; GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 +; options passed: -iprefix -mtune=pentiumpro -auxbase +; options enabled: -feliminate-unused-debug-types -fpeephole +; -ffunction-cse -fkeep-static-consts -fpcc-struct-return -fgcse-lm +; -fgcse-sm -fsched-interblock -fsched-spec -fbranch-count-reg -fcommon +; -fgnu-linker -fargument-alias -fzero-initialized-in-bss -fident +; -fmath-errno -ftrapping-math -m80387 -mhard-float -mno-soft-float +; -mieee-fp -mfp-ret-in-387 -maccumulate-outgoing-args -mno-red-zone +; -mtls-direct-seg-refs -mtune=pentiumpro -march=i386 + +target triple = "i686-pc-linux-gnu" +target pointersize = 32 +target endian = little +deplibs = ["c", "crtend"] + +"complex double" = type { double, double } +"complex float" = type { float, float } +"complex long double" = type { double, double } + +implementation +declare double %acos(double) ;; __builtin_acos +declare float %acosf(float) ;; __builtin_acosf +declare double %acosh(double) ;; __builtin_acosh +declare float %acoshf(float) ;; __builtin_acoshf +declare double %acoshl(double) ;; __builtin_acoshl +declare double %acosl(double) ;; __builtin_acosl +declare double %asin(double) ;; __builtin_asin +declare float %asinf(float) ;; __builtin_asinf +declare double %asinh(double) ;; __builtin_asinh +declare float %asinhf(float) ;; __builtin_asinhf +declare double %asinhl(double) ;; __builtin_asinhl +declare double %asinl(double) ;; __builtin_asinl +declare double %atan(double) ;; __builtin_atan +declare double %atan2(double,double) ;; __builtin_atan2 +declare float %atan2f(float,float) ;; __builtin_atan2f +declare double %atan2l(double,double) ;; __builtin_atan2l +declare float %atanf(float) ;; __builtin_atanf +declare double %atanh(double) ;; __builtin_atanh +declare float %atanhf(float) ;; __builtin_atanhf +declare double %atanhl(double) ;; __builtin_atanhl +declare double %atanl(double) ;; __builtin_atanl +declare double %cbrt(double) ;; __builtin_cbrt +declare float %cbrtf(float) ;; __builtin_cbrtf +declare double %cbrtl(double) ;; __builtin_cbrtl +declare double %ceil(double) ;; __builtin_ceil +declare float %ceilf(float) ;; __builtin_ceilf +declare double %ceill(double) ;; __builtin_ceill +declare double %copysign(double,double) ;; __builtin_copysign +declare float %copysignf(float,float) ;; __builtin_copysignf +declare double %copysignl(double,double) ;; __builtin_copysignl +declare double %cos(double) ;; __builtin_cos +declare float %cosf(float) ;; __builtin_cosf +declare double %cosh(double) ;; __builtin_cosh +declare float %coshf(float) ;; __builtin_coshf +declare double %coshl(double) ;; __builtin_coshl +declare double %cosl(double) ;; __builtin_cosl +declare double %drem(double,double) ;; __builtin_drem +declare float %dremf(float,float) ;; __builtin_dremf +declare double %dreml(double,double) ;; __builtin_dreml +declare double %erf(double) ;; __builtin_erf +declare double %erfc(double) ;; __builtin_erfc +declare float %erfcf(float) ;; __builtin_erfcf +declare double %erfcl(double) ;; __builtin_erfcl +declare float %erff(float) ;; __builtin_erff +declare double %erfl(double) ;; __builtin_erfl +declare double %exp(double) ;; __builtin_exp +declare double %exp10(double) ;; __builtin_exp10 +declare float %exp10f(float) ;; __builtin_exp10f +declare double %exp10l(double) ;; __builtin_exp10l +declare double %exp2(double) ;; __builtin_exp2 +declare float %exp2f(float) ;; __builtin_exp2f +declare double %exp2l(double) ;; __builtin_exp2l +declare float %expf(float) ;; __builtin_expf +declare double %expl(double) ;; __builtin_expl +declare double %expm1(double) ;; __builtin_expm1 +declare float %expm1f(float) ;; __builtin_expm1f +declare double %expm1l(double) ;; __builtin_expm1l +declare double %fabs(double) ;; __builtin_fabs +declare float %fabsf(float) ;; __builtin_fabsf +declare double %fabsl(double) ;; __builtin_fabsl +declare double %fdim(double,double) ;; __builtin_fdim +declare float %fdimf(float,float) ;; __builtin_fdimf +declare double %fdiml(double,double) ;; __builtin_fdiml +declare double %floor(double) ;; __builtin_floor +declare float %floorf(float) ;; __builtin_floorf +declare double %floorl(double) ;; __builtin_floorl +declare double %fma(double,double,double) ;; __builtin_fma +declare float %fmaf(float,float,float) ;; __builtin_fmaf +declare double %fmal(double,double,double) ;; __builtin_fmal +declare double %fmax(double,double) ;; __builtin_fmax +declare float %fmaxf(float,float) ;; __builtin_fmaxf +declare double %fmaxl(double,double) ;; __builtin_fmaxl +declare double %fmin(double,double) ;; __builtin_fmin +declare float %fminf(float,float) ;; __builtin_fminf +declare double %fminl(double,double) ;; __builtin_fminl +declare double %fmod(double,double) ;; __builtin_fmod +declare float %fmodf(float,float) ;; __builtin_fmodf +declare double %fmodl(double,double) ;; __builtin_fmodl +declare double %frexp(double,int*) ;; __builtin_frexp +declare float %frexpf(float,int*) ;; __builtin_frexpf +declare double %frexpl(double,int*) ;; __builtin_frexpl +declare double %gamma(double) ;; __builtin_gamma +declare float %gammaf(float) ;; __builtin_gammaf +declare double %gammal(double) ;; __builtin_gammal +declare double %__builtin_huge_val() +declare float %__builtin_huge_valf() +declare double %__builtin_huge_vall() +declare double %hypot(double,double) ;; __builtin_hypot +declare float %hypotf(float,float) ;; __builtin_hypotf +declare double %hypotl(double,double) ;; __builtin_hypotl +declare int %ilogb(double) ;; __builtin_ilogb +declare int %ilogbf(float) ;; __builtin_ilogbf +declare int %ilogbl(double) ;; __builtin_ilogbl +declare double %__builtin_inf() +declare float %__builtin_inff() +declare double %__builtin_infl() +declare double %j0(double) ;; __builtin_j0 +declare float %j0f(float) ;; __builtin_j0f +declare double %j0l(double) ;; __builtin_j0l +declare double %j1(double) ;; __builtin_j1 +declare float %j1f(float) ;; __builtin_j1f +declare double %j1l(double) ;; __builtin_j1l +declare double %jn(int,double) ;; __builtin_jn +declare float %jnf(int,float) ;; __builtin_jnf +declare double %jnl(int,double) ;; __builtin_jnl +declare double %ldexp(double,int) ;; __builtin_ldexp +declare float %ldexpf(float,int) ;; __builtin_ldexpf +declare double %ldexpl(double,int) ;; __builtin_ldexpl +declare double %lgamma(double) ;; __builtin_lgamma +declare float %lgammaf(float) ;; __builtin_lgammaf +declare double %lgammal(double) ;; __builtin_lgammal +declare long %llrint(double) ;; __builtin_llrint +declare long %llrintf(float) ;; __builtin_llrintf +declare long %llrintl(double) ;; __builtin_llrintl +declare long %llround(double) ;; __builtin_llround +declare long %llroundf(float) ;; __builtin_llroundf +declare long %llroundl(double) ;; __builtin_llroundl +declare double %log(double) ;; __builtin_log +declare double %log10(double) ;; __builtin_log10 +declare float %log10f(float) ;; __builtin_log10f +declare double %log10l(double) ;; __builtin_log10l +declare double %log1p(double) ;; __builtin_log1p +declare float %log1pf(float) ;; __builtin_log1pf +declare double %log1pl(double) ;; __builtin_log1pl +declare double %log2(double) ;; __builtin_log2 +declare float %log2f(float) ;; __builtin_log2f +declare double %log2l(double) ;; __builtin_log2l +declare double %logb(double) ;; __builtin_logb +declare float %logbf(float) ;; __builtin_logbf +declare double %logbl(double) ;; __builtin_logbl +declare float %logf(float) ;; __builtin_logf +declare double %logl(double) ;; __builtin_logl +declare int %lrint(double) ;; __builtin_lrint +declare int %lrintf(float) ;; __builtin_lrintf +declare int %lrintl(double) ;; __builtin_lrintl +declare int %lround(double) ;; __builtin_lround +declare int %lroundf(float) ;; __builtin_lroundf +declare int %lroundl(double) ;; __builtin_lroundl +declare double %modf(double,double*) ;; __builtin_modf +declare float %modff(float,float*) ;; __builtin_modff +declare double %modfl(double,double*) ;; __builtin_modfl +declare double %nan(sbyte*) ;; __builtin_nan +declare float %nanf(sbyte*) ;; __builtin_nanf +declare double %nanl(sbyte*) ;; __builtin_nanl +declare double %nans(sbyte*) ;; __builtin_nans +declare float %nansf(sbyte*) ;; __builtin_nansf +declare double %nansl(sbyte*) ;; __builtin_nansl +declare double %nearbyint(double) ;; __builtin_nearbyint +declare float %nearbyintf(float) ;; __builtin_nearbyintf +declare double %nearbyintl(double) ;; __builtin_nearbyintl +declare double %nextafter(double,double) ;; __builtin_nextafter +declare float %nextafterf(float,float) ;; __builtin_nextafterf +declare double %nextafterl(double,double) ;; __builtin_nextafterl +declare double %nexttoward(double,double) ;; __builtin_nexttoward +declare float %nexttowardf(float,double) ;; __builtin_nexttowardf +declare double %nexttowardl(double,double) ;; __builtin_nexttowardl +declare double %pow(double,double) ;; __builtin_pow +declare double %pow10(double) ;; __builtin_pow10 +declare float %pow10f(float) ;; __builtin_pow10f +declare double %pow10l(double) ;; __builtin_pow10l +declare float %powf(float,float) ;; __builtin_powf +declare double %powl(double,double) ;; __builtin_powl +declare double %remainder(double,double) ;; __builtin_remainder +declare float %remainderf(float,float) ;; __builtin_remainderf +declare double %remainderl(double,double) ;; __builtin_remainderl +declare double %remquo(double,double,int*) ;; __builtin_remquo +declare float %remquof(float,float,int*) ;; __builtin_remquof +declare double %remquol(double,double,int*) ;; __builtin_remquol +declare double %rint(double) ;; __builtin_rint +declare float %rintf(float) ;; __builtin_rintf +declare double %rintl(double) ;; __builtin_rintl +declare double %round(double) ;; __builtin_round +declare float %roundf(float) ;; __builtin_roundf +declare double %roundl(double) ;; __builtin_roundl +declare double %scalb(double,double) ;; __builtin_scalb +declare float %scalbf(float,float) ;; __builtin_scalbf +declare double %scalbl(double,double) ;; __builtin_scalbl +declare double %scalbln(double,int) ;; __builtin_scalbln +declare float %scalblnf(float,int) ;; __builtin_scalblnf +declare double %scalblnl(double,int) ;; __builtin_scalblnl +declare double %scalbn(double,int) ;; __builtin_scalbn +declare float %scalbnf(float,int) ;; __builtin_scalbnf +declare double %scalbnl(double,int) ;; __builtin_scalbnl +declare double %significand(double) ;; __builtin_significand +declare float %significandf(float) ;; __builtin_significandf +declare double %significandl(double) ;; __builtin_significandl +declare double %sin(double) ;; __builtin_sin +declare void %sincos(double,double*,double*) ;; __builtin_sincos +declare void %sincosf(float,float*,float*) ;; __builtin_sincosf +declare void %sincosl(double,double*,double*) ;; __builtin_sincosl +declare float %sinf(float) ;; __builtin_sinf +declare double %sinh(double) ;; __builtin_sinh +declare float %sinhf(float) ;; __builtin_sinhf +declare double %sinhl(double) ;; __builtin_sinhl +declare double %sinl(double) ;; __builtin_sinl +declare double %sqrt(double) ;; __builtin_sqrt +declare float %sqrtf(float) ;; __builtin_sqrtf +declare double %sqrtl(double) ;; __builtin_sqrtl +declare double %tan(double) ;; __builtin_tan +declare float %tanf(float) ;; __builtin_tanf +declare double %tanh(double) ;; __builtin_tanh +declare float %tanhf(float) ;; __builtin_tanhf +declare double %tanhl(double) ;; __builtin_tanhl +declare double %tanl(double) ;; __builtin_tanl +declare double %tgamma(double) ;; __builtin_tgamma +declare float %tgammaf(float) ;; __builtin_tgammaf +declare double %tgammal(double) ;; __builtin_tgammal +declare double %trunc(double) ;; __builtin_trunc +declare float %truncf(float) ;; __builtin_truncf +declare double %truncl(double) ;; __builtin_truncl +declare double %y0(double) ;; __builtin_y0 +declare float %y0f(float) ;; __builtin_y0f +declare double %y0l(double) ;; __builtin_y0l +declare double %y1(double) ;; __builtin_y1 +declare float %y1f(float) ;; __builtin_y1f +declare double %y1l(double) ;; __builtin_y1l +declare double %yn(int,double) ;; __builtin_yn +declare float %ynf(int,float) ;; __builtin_ynf +declare double %ynl(int,double) ;; __builtin_ynl +declare double %cabs(double,double) ;; __builtin_cabs +declare float %cabsf(float,float) ;; __builtin_cabsf +declare double %cabsl(double,double) ;; __builtin_cabsl +declare void %cacos("complex double"*,double,double) ;; __builtin_cacos +declare void %cacosf("complex float"*,float,float) ;; __builtin_cacosf +declare void %cacosh("complex double"*,double,double) ;; __builtin_cacosh +declare void %cacoshf("complex float"*,float,float) ;; __builtin_cacoshf +declare void %cacoshl("complex long double"*,double,double) ;; __builtin_cacoshl +declare void %cacosl("complex long double"*,double,double) ;; __builtin_cacosl +declare double %carg(double,double) ;; __builtin_carg +declare float %cargf(float,float) ;; __builtin_cargf +declare double %cargl(double,double) ;; __builtin_cargl +declare void %casin("complex double"*,double,double) ;; __builtin_casin +declare void %casinf("complex float"*,float,float) ;; __builtin_casinf +declare void %casinh("complex double"*,double,double) ;; __builtin_casinh +declare void %casinhf("complex float"*,float,float) ;; __builtin_casinhf +declare void %casinhl("complex long double"*,double,double) ;; __builtin_casinhl +declare void %casinl("complex long double"*,double,double) ;; __builtin_casinl +declare void %catan("complex double"*,double,double) ;; __builtin_catan +declare void %catanf("complex float"*,float,float) ;; __builtin_catanf +declare void %catanh("complex double"*,double,double) ;; __builtin_catanh +declare void %catanhf("complex float"*,float,float) ;; __builtin_catanhf +declare void %catanhl("complex long double"*,double,double) ;; __builtin_catanhl +declare void %catanl("complex long double"*,double,double) ;; __builtin_catanl +declare void %ccos("complex double"*,double,double) ;; __builtin_ccos +declare void %ccosf("complex float"*,float,float) ;; __builtin_ccosf +declare void %ccosh("complex double"*,double,double) ;; __builtin_ccosh +declare void %ccoshf("complex float"*,float,float) ;; __builtin_ccoshf +declare void %ccoshl("complex long double"*,double,double) ;; __builtin_ccoshl +declare void %ccosl("complex long double"*,double,double) ;; __builtin_ccosl +declare void %cexp("complex double"*,double,double) ;; __builtin_cexp +declare void %cexpf("complex float"*,float,float) ;; __builtin_cexpf +declare void %cexpl("complex long double"*,double,double) ;; __builtin_cexpl +declare double %cimag(double,double) ;; __builtin_cimag +declare float %cimagf(float,float) ;; __builtin_cimagf +declare double %cimagl(double,double) ;; __builtin_cimagl +declare void %conj("complex double"*,double,double) ;; __builtin_conj +declare void %conjf("complex float"*,float,float) ;; __builtin_conjf +declare void %conjl("complex long double"*,double,double) ;; __builtin_conjl +declare void %cpow("complex double"*,double,double,double,double) ;; __builtin_cpow +declare void %cpowf("complex float"*,float,float,float,float) ;; __builtin_cpowf +declare void %cpowl("complex long double"*,double,double,double,double) ;; __builtin_cpowl +declare void %cproj("complex double"*,double,double) ;; __builtin_cproj +declare void %cprojf("complex float"*,float,float) ;; __builtin_cprojf +declare void %cprojl("complex long double"*,double,double) ;; __builtin_cprojl +declare double %creal(double,double) ;; __builtin_creal +declare float %crealf(float,float) ;; __builtin_crealf +declare double %creall(double,double) ;; __builtin_creall +declare void %csin("complex double"*,double,double) ;; __builtin_csin +declare void %csinf("complex float"*,float,float) ;; __builtin_csinf +declare void %csinh("complex double"*,double,double) ;; __builtin_csinh +declare void %csinhf("complex float"*,float,float) ;; __builtin_csinhf +declare void %csinhl("complex long double"*,double,double) ;; __builtin_csinhl +declare void %csinl("complex long double"*,double,double) ;; __builtin_csinl +declare void %csqrt("complex double"*,double,double) ;; __builtin_csqrt +declare void %csqrtf("complex float"*,float,float) ;; __builtin_csqrtf +declare void %csqrtl("complex long double"*,double,double) ;; __builtin_csqrtl +declare void %ctan("complex double"*,double,double) ;; __builtin_ctan +declare void %ctanf("complex float"*,float,float) ;; __builtin_ctanf +declare void %ctanh("complex double"*,double,double) ;; __builtin_ctanh +declare void %ctanhf("complex float"*,float,float) ;; __builtin_ctanhf +declare void %ctanhl("complex long double"*,double,double) ;; __builtin_ctanhl +declare void %ctanl("complex long double"*,double,double) ;; __builtin_ctanl +declare int %bcmp(sbyte*,sbyte*,uint) ;; __builtin_bcmp +declare void %bcopy(sbyte*,sbyte*,uint) ;; __builtin_bcopy +declare void %bzero(sbyte*,uint) ;; __builtin_bzero +declare int %ffs(int) ;; __builtin_ffs +declare int %ffsl(int) ;; __builtin_ffsl +declare int %ffsll(long) ;; __builtin_ffsll +declare sbyte* %index(sbyte*,int) ;; __builtin_index +declare int %memcmp(sbyte*,sbyte*,uint) ;; __builtin_memcmp +declare sbyte* %memcpy(sbyte*,sbyte*,uint) ;; __builtin_memcpy +declare sbyte* %memmove(sbyte*,sbyte*,uint) ;; __builtin_memmove +declare sbyte* %mempcpy(sbyte*,sbyte*,uint) ;; __builtin_mempcpy +declare sbyte* %memset(sbyte*,int,uint) ;; __builtin_memset +declare sbyte* %rindex(sbyte*,int) ;; __builtin_rindex +declare sbyte* %stpcpy(sbyte*,sbyte*) ;; __builtin_stpcpy +declare sbyte* %strcat(sbyte*,sbyte*) ;; __builtin_strcat +declare sbyte* %strchr(sbyte*,int) ;; __builtin_strchr +declare int %strcmp(sbyte*,sbyte*) ;; __builtin_strcmp +declare sbyte* %strcpy(sbyte*,sbyte*) ;; __builtin_strcpy +declare uint %strcspn(sbyte*,sbyte*) ;; __builtin_strcspn +declare sbyte* %strdup(sbyte*) ;; __builtin_strdup +declare uint %strlen(sbyte*) ;; __builtin_strlen +declare sbyte* %strncat(sbyte*,sbyte*,uint) ;; __builtin_strncat +declare int %strncmp(sbyte*,sbyte*,uint) ;; __builtin_strncmp +declare sbyte* %strncpy(sbyte*,sbyte*,uint) ;; __builtin_strncpy +declare sbyte* %strpbrk(sbyte*,sbyte*) ;; __builtin_strpbrk +declare sbyte* %strrchr(sbyte*,int) ;; __builtin_strrchr +declare uint %strspn(sbyte*,sbyte*) ;; __builtin_strspn +declare sbyte* %strstr(sbyte*,sbyte*) ;; __builtin_strstr +declare int %fprintf(sbyte*,sbyte*, ...) ;; __builtin_fprintf +declare int %fprintf_unlocked(sbyte*,sbyte*, ...) ;; __builtin_fprintf_unlocked +declare int %fputc(int,sbyte*) ;; __builtin_fputc +declare int %fputc_unlocked(int,sbyte*) ;; __builtin_fputc_unlocked +declare int %fputs(sbyte*,sbyte*) ;; __builtin_fputs +declare int %fputs_unlocked(sbyte*,sbyte*) ;; __builtin_fputs_unlocked +declare int %fscanf(sbyte*,sbyte*, ...) ;; __builtin_fscanf +declare uint %fwrite(sbyte*,uint,uint,sbyte*) ;; __builtin_fwrite +declare uint %fwrite_unlocked(sbyte*,uint,uint,sbyte*) ;; __builtin_fwrite_unlocked +declare int %printf(sbyte*, ...) ;; __builtin_printf +declare int %printf_unlocked(sbyte*, ...) ;; __builtin_printf_unlocked +declare int %putchar(int) ;; __builtin_putchar +declare int %putchar_unlocked(int) ;; __builtin_putchar_unlocked +declare int %puts(sbyte*) ;; __builtin_puts +declare int %puts_unlocked(sbyte*) ;; __builtin_puts_unlocked +declare int %scanf(sbyte*, ...) ;; __builtin_scanf +declare int %snprintf(sbyte*,uint,sbyte*, ...) ;; __builtin_snprintf +declare int %sprintf(sbyte*,sbyte*, ...) ;; __builtin_sprintf +declare int %sscanf(sbyte*,sbyte*, ...) ;; __builtin_sscanf +declare int %vfprintf(sbyte*,sbyte*,sbyte*) ;; __builtin_vfprintf +declare int %vfscanf(sbyte*,sbyte*,sbyte*) ;; __builtin_vfscanf +declare int %vprintf(sbyte*,sbyte*) ;; __builtin_vprintf +declare int %vscanf(sbyte*,sbyte*) ;; __builtin_vscanf +declare int %vsnprintf(sbyte*,uint,sbyte*,sbyte*) ;; __builtin_vsnprintf +declare int %vsprintf(sbyte*,sbyte*,sbyte*) ;; __builtin_vsprintf +declare int %vsscanf(sbyte*,sbyte*,sbyte*) ;; __builtin_vsscanf +declare void %abort() ;; __builtin_abort +declare int %abs(int) ;; __builtin_abs +declare sbyte* %__builtin_aggregate_incoming_address(...) +declare sbyte* %alloca(uint) ;; __builtin_alloca +declare sbyte* %__builtin_apply(void (...)*,sbyte*,uint) +declare sbyte* %__builtin_apply_args(...) +declare int %__builtin_args_info(int) +declare sbyte* %calloc(uint,uint) ;; __builtin_calloc +declare int %__builtin_classify_type(...) +declare int %__builtin_clz(int) +declare int %__builtin_clzl(int) +declare int %__builtin_clzll(long) +declare int %__builtin_constant_p(...) +declare int %__builtin_ctz(int) +declare int %__builtin_ctzl(int) +declare int %__builtin_ctzll(long) +declare sbyte* %dcgettext(sbyte*,sbyte*,int) ;; __builtin_dcgettext +declare sbyte* %dgettext(sbyte*,sbyte*) ;; __builtin_dgettext +declare sbyte* %__builtin_dwarf_cfa() +declare uint %__builtin_dwarf_sp_column() +declare void %__builtin_eh_return(int,sbyte*) +declare int %__builtin_eh_return_data_regno(int) +declare void %exit(int) ;; __builtin_exit +declare int %__builtin_expect(int,int) +declare sbyte* %__builtin_extract_return_addr(sbyte*) +declare sbyte* %__builtin_frame_address(uint) +declare sbyte* %__builtin_frob_return_addr(sbyte*) +declare sbyte* %gettext(sbyte*) ;; __builtin_gettext +declare long %imaxabs(long) ;; __builtin_imaxabs +declare void %__builtin_init_dwarf_reg_size_table(sbyte*) +declare int %__builtin_isgreater(...) +declare int %__builtin_isgreaterequal(...) +declare int %__builtin_isless(...) +declare int %__builtin_islessequal(...) +declare int %__builtin_islessgreater(...) +declare int %__builtin_isunordered(...) +declare int %labs(int) ;; __builtin_labs +declare long %llabs(long) ;; __builtin_llabs +declare void %__builtin_longjmp(sbyte*,int) +declare sbyte* %malloc(uint) ;; __builtin_malloc +declare sbyte* %__builtin_next_arg(...) +declare int %__builtin_parity(int) +declare int %__builtin_parityl(int) +declare int %__builtin_parityll(long) +declare int %__builtin_popcount(int) +declare int %__builtin_popcountl(int) +declare int %__builtin_popcountll(long) +declare void %__builtin_prefetch(sbyte*, ...) +declare void %__builtin_return(sbyte*) +declare sbyte* %__builtin_return_address(uint) +declare sbyte* %__builtin_saveregs(...) +declare int %__builtin_setjmp(sbyte*) +declare void %__builtin_stdarg_start(sbyte**, ...) +declare int %strfmon(sbyte*,uint,sbyte*, ...) ;; __builtin_strfmon +declare uint %strftime(sbyte*,uint,sbyte*,sbyte*) ;; __builtin_strftime +declare void %__builtin_trap() +declare void %__builtin_unwind_init() +declare void %__builtin_va_copy(sbyte**,sbyte*) +declare void %__builtin_va_end(sbyte**) +declare void %__builtin_va_start(sbyte**, ...) +declare void %_exit(int) ;; __builtin__exit +declare void %_Exit(int) ;; __builtin__Exit + +int %add(int %n, int %y) { +entry: + %n_addr = alloca int ; ty=int* + %y_addr = alloca int ; ty=int* + %result = alloca int ; ty=int* + store int %n, int* %n_addr + store int %y, int* %y_addr + %tmp.0 = load int* %n_addr ; ty=int + %tmp.1 = load int* %y_addr ; ty=int + %tmp.2 = add int %tmp.0, %tmp.1 ; ty=int + store int %tmp.2, int* %result + br label %return +after_ret: + br label %return +return: + %tmp.3 = load int* %result ; ty=int + ret int %tmp.3 +} + +;; Created by "GCC: (GNU) 3.4-llvm 20051104 (LLVM 1.6)" Added: pypy/dist/pypy/translator/llvm/pyllvm/test/hello.c ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/hello.c Wed Mar 1 01:31:52 2006 @@ -0,0 +1,9 @@ +char *gethellostr() { + return "hello world\n"; +} + +int hello() { + printf(gethellostr()); + return 0; +} + Added: pypy/dist/pypy/translator/llvm/pyllvm/test/hello.s ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/hello.s Wed Mar 1 01:31:52 2006 @@ -0,0 +1,451 @@ +; GNU C version 3.4-llvm 20051104 (LLVM 1.6) (i686-pc-linux-gnu) +; compiled by GNU C version 3.4.0. +; GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 +; options passed: -iprefix -mtune=pentiumpro -auxbase +; options enabled: -feliminate-unused-debug-types -fpeephole +; -ffunction-cse -fkeep-static-consts -fpcc-struct-return -fgcse-lm +; -fgcse-sm -fsched-interblock -fsched-spec -fbranch-count-reg -fcommon +; -fgnu-linker -fargument-alias -fzero-initialized-in-bss -fident +; -fmath-errno -ftrapping-math -m80387 -mhard-float -mno-soft-float +; -mieee-fp -mfp-ret-in-387 -maccumulate-outgoing-args -mno-red-zone +; -mtls-direct-seg-refs -mtune=pentiumpro -march=i386 + +target triple = "i686-pc-linux-gnu" +target pointersize = 32 +target endian = little +deplibs = ["c", "crtend"] + +"complex double" = type { double, double } +"complex float" = type { float, float } +"complex long double" = type { double, double } +%.str_1 = internal constant [13 x sbyte] c"hello world\0A\00" + + +implementation +declare double %acos(double) ;; __builtin_acos +declare float %acosf(float) ;; __builtin_acosf +declare double %acosh(double) ;; __builtin_acosh +declare float %acoshf(float) ;; __builtin_acoshf +declare double %acoshl(double) ;; __builtin_acoshl +declare double %acosl(double) ;; __builtin_acosl +declare double %asin(double) ;; __builtin_asin +declare float %asinf(float) ;; __builtin_asinf +declare double %asinh(double) ;; __builtin_asinh +declare float %asinhf(float) ;; __builtin_asinhf +declare double %asinhl(double) ;; __builtin_asinhl +declare double %asinl(double) ;; __builtin_asinl +declare double %atan(double) ;; __builtin_atan +declare double %atan2(double,double) ;; __builtin_atan2 +declare float %atan2f(float,float) ;; __builtin_atan2f +declare double %atan2l(double,double) ;; __builtin_atan2l +declare float %atanf(float) ;; __builtin_atanf +declare double %atanh(double) ;; __builtin_atanh +declare float %atanhf(float) ;; __builtin_atanhf +declare double %atanhl(double) ;; __builtin_atanhl +declare double %atanl(double) ;; __builtin_atanl +declare double %cbrt(double) ;; __builtin_cbrt +declare float %cbrtf(float) ;; __builtin_cbrtf +declare double %cbrtl(double) ;; __builtin_cbrtl +declare double %ceil(double) ;; __builtin_ceil +declare float %ceilf(float) ;; __builtin_ceilf +declare double %ceill(double) ;; __builtin_ceill +declare double %copysign(double,double) ;; __builtin_copysign +declare float %copysignf(float,float) ;; __builtin_copysignf +declare double %copysignl(double,double) ;; __builtin_copysignl +declare double %cos(double) ;; __builtin_cos +declare float %cosf(float) ;; __builtin_cosf +declare double %cosh(double) ;; __builtin_cosh +declare float %coshf(float) ;; __builtin_coshf +declare double %coshl(double) ;; __builtin_coshl +declare double %cosl(double) ;; __builtin_cosl +declare double %drem(double,double) ;; __builtin_drem +declare float %dremf(float,float) ;; __builtin_dremf +declare double %dreml(double,double) ;; __builtin_dreml +declare double %erf(double) ;; __builtin_erf +declare double %erfc(double) ;; __builtin_erfc +declare float %erfcf(float) ;; __builtin_erfcf +declare double %erfcl(double) ;; __builtin_erfcl +declare float %erff(float) ;; __builtin_erff +declare double %erfl(double) ;; __builtin_erfl +declare double %exp(double) ;; __builtin_exp +declare double %exp10(double) ;; __builtin_exp10 +declare float %exp10f(float) ;; __builtin_exp10f +declare double %exp10l(double) ;; __builtin_exp10l +declare double %exp2(double) ;; __builtin_exp2 +declare float %exp2f(float) ;; __builtin_exp2f +declare double %exp2l(double) ;; __builtin_exp2l +declare float %expf(float) ;; __builtin_expf +declare double %expl(double) ;; __builtin_expl +declare double %expm1(double) ;; __builtin_expm1 +declare float %expm1f(float) ;; __builtin_expm1f +declare double %expm1l(double) ;; __builtin_expm1l +declare double %fabs(double) ;; __builtin_fabs +declare float %fabsf(float) ;; __builtin_fabsf +declare double %fabsl(double) ;; __builtin_fabsl +declare double %fdim(double,double) ;; __builtin_fdim +declare float %fdimf(float,float) ;; __builtin_fdimf +declare double %fdiml(double,double) ;; __builtin_fdiml +declare double %floor(double) ;; __builtin_floor +declare float %floorf(float) ;; __builtin_floorf +declare double %floorl(double) ;; __builtin_floorl +declare double %fma(double,double,double) ;; __builtin_fma +declare float %fmaf(float,float,float) ;; __builtin_fmaf +declare double %fmal(double,double,double) ;; __builtin_fmal +declare double %fmax(double,double) ;; __builtin_fmax +declare float %fmaxf(float,float) ;; __builtin_fmaxf +declare double %fmaxl(double,double) ;; __builtin_fmaxl +declare double %fmin(double,double) ;; __builtin_fmin +declare float %fminf(float,float) ;; __builtin_fminf +declare double %fminl(double,double) ;; __builtin_fminl +declare double %fmod(double,double) ;; __builtin_fmod +declare float %fmodf(float,float) ;; __builtin_fmodf +declare double %fmodl(double,double) ;; __builtin_fmodl +declare double %frexp(double,int*) ;; __builtin_frexp +declare float %frexpf(float,int*) ;; __builtin_frexpf +declare double %frexpl(double,int*) ;; __builtin_frexpl +declare double %gamma(double) ;; __builtin_gamma +declare float %gammaf(float) ;; __builtin_gammaf +declare double %gammal(double) ;; __builtin_gammal +declare double %__builtin_huge_val() +declare float %__builtin_huge_valf() +declare double %__builtin_huge_vall() +declare double %hypot(double,double) ;; __builtin_hypot +declare float %hypotf(float,float) ;; __builtin_hypotf +declare double %hypotl(double,double) ;; __builtin_hypotl +declare int %ilogb(double) ;; __builtin_ilogb +declare int %ilogbf(float) ;; __builtin_ilogbf +declare int %ilogbl(double) ;; __builtin_ilogbl +declare double %__builtin_inf() +declare float %__builtin_inff() +declare double %__builtin_infl() +declare double %j0(double) ;; __builtin_j0 +declare float %j0f(float) ;; __builtin_j0f +declare double %j0l(double) ;; __builtin_j0l +declare double %j1(double) ;; __builtin_j1 +declare float %j1f(float) ;; __builtin_j1f +declare double %j1l(double) ;; __builtin_j1l +declare double %jn(int,double) ;; __builtin_jn +declare float %jnf(int,float) ;; __builtin_jnf +declare double %jnl(int,double) ;; __builtin_jnl +declare double %ldexp(double,int) ;; __builtin_ldexp +declare float %ldexpf(float,int) ;; __builtin_ldexpf +declare double %ldexpl(double,int) ;; __builtin_ldexpl +declare double %lgamma(double) ;; __builtin_lgamma +declare float %lgammaf(float) ;; __builtin_lgammaf +declare double %lgammal(double) ;; __builtin_lgammal +declare long %llrint(double) ;; __builtin_llrint +declare long %llrintf(float) ;; __builtin_llrintf +declare long %llrintl(double) ;; __builtin_llrintl +declare long %llround(double) ;; __builtin_llround +declare long %llroundf(float) ;; __builtin_llroundf +declare long %llroundl(double) ;; __builtin_llroundl +declare double %log(double) ;; __builtin_log +declare double %log10(double) ;; __builtin_log10 +declare float %log10f(float) ;; __builtin_log10f +declare double %log10l(double) ;; __builtin_log10l +declare double %log1p(double) ;; __builtin_log1p +declare float %log1pf(float) ;; __builtin_log1pf +declare double %log1pl(double) ;; __builtin_log1pl +declare double %log2(double) ;; __builtin_log2 +declare float %log2f(float) ;; __builtin_log2f +declare double %log2l(double) ;; __builtin_log2l +declare double %logb(double) ;; __builtin_logb +declare float %logbf(float) ;; __builtin_logbf +declare double %logbl(double) ;; __builtin_logbl +declare float %logf(float) ;; __builtin_logf +declare double %logl(double) ;; __builtin_logl +declare int %lrint(double) ;; __builtin_lrint +declare int %lrintf(float) ;; __builtin_lrintf +declare int %lrintl(double) ;; __builtin_lrintl +declare int %lround(double) ;; __builtin_lround +declare int %lroundf(float) ;; __builtin_lroundf +declare int %lroundl(double) ;; __builtin_lroundl +declare double %modf(double,double*) ;; __builtin_modf +declare float %modff(float,float*) ;; __builtin_modff +declare double %modfl(double,double*) ;; __builtin_modfl +declare double %nan(sbyte*) ;; __builtin_nan +declare float %nanf(sbyte*) ;; __builtin_nanf +declare double %nanl(sbyte*) ;; __builtin_nanl +declare double %nans(sbyte*) ;; __builtin_nans +declare float %nansf(sbyte*) ;; __builtin_nansf +declare double %nansl(sbyte*) ;; __builtin_nansl +declare double %nearbyint(double) ;; __builtin_nearbyint +declare float %nearbyintf(float) ;; __builtin_nearbyintf +declare double %nearbyintl(double) ;; __builtin_nearbyintl +declare double %nextafter(double,double) ;; __builtin_nextafter +declare float %nextafterf(float,float) ;; __builtin_nextafterf +declare double %nextafterl(double,double) ;; __builtin_nextafterl +declare double %nexttoward(double,double) ;; __builtin_nexttoward +declare float %nexttowardf(float,double) ;; __builtin_nexttowardf +declare double %nexttowardl(double,double) ;; __builtin_nexttowardl +declare double %pow(double,double) ;; __builtin_pow +declare double %pow10(double) ;; __builtin_pow10 +declare float %pow10f(float) ;; __builtin_pow10f +declare double %pow10l(double) ;; __builtin_pow10l +declare float %powf(float,float) ;; __builtin_powf +declare double %powl(double,double) ;; __builtin_powl +declare double %remainder(double,double) ;; __builtin_remainder +declare float %remainderf(float,float) ;; __builtin_remainderf +declare double %remainderl(double,double) ;; __builtin_remainderl +declare double %remquo(double,double,int*) ;; __builtin_remquo +declare float %remquof(float,float,int*) ;; __builtin_remquof +declare double %remquol(double,double,int*) ;; __builtin_remquol +declare double %rint(double) ;; __builtin_rint +declare float %rintf(float) ;; __builtin_rintf +declare double %rintl(double) ;; __builtin_rintl +declare double %round(double) ;; __builtin_round +declare float %roundf(float) ;; __builtin_roundf +declare double %roundl(double) ;; __builtin_roundl +declare double %scalb(double,double) ;; __builtin_scalb +declare float %scalbf(float,float) ;; __builtin_scalbf +declare double %scalbl(double,double) ;; __builtin_scalbl +declare double %scalbln(double,int) ;; __builtin_scalbln +declare float %scalblnf(float,int) ;; __builtin_scalblnf +declare double %scalblnl(double,int) ;; __builtin_scalblnl +declare double %scalbn(double,int) ;; __builtin_scalbn +declare float %scalbnf(float,int) ;; __builtin_scalbnf +declare double %scalbnl(double,int) ;; __builtin_scalbnl +declare double %significand(double) ;; __builtin_significand +declare float %significandf(float) ;; __builtin_significandf +declare double %significandl(double) ;; __builtin_significandl +declare double %sin(double) ;; __builtin_sin +declare void %sincos(double,double*,double*) ;; __builtin_sincos +declare void %sincosf(float,float*,float*) ;; __builtin_sincosf +declare void %sincosl(double,double*,double*) ;; __builtin_sincosl +declare float %sinf(float) ;; __builtin_sinf +declare double %sinh(double) ;; __builtin_sinh +declare float %sinhf(float) ;; __builtin_sinhf +declare double %sinhl(double) ;; __builtin_sinhl +declare double %sinl(double) ;; __builtin_sinl +declare double %sqrt(double) ;; __builtin_sqrt +declare float %sqrtf(float) ;; __builtin_sqrtf +declare double %sqrtl(double) ;; __builtin_sqrtl +declare double %tan(double) ;; __builtin_tan +declare float %tanf(float) ;; __builtin_tanf +declare double %tanh(double) ;; __builtin_tanh +declare float %tanhf(float) ;; __builtin_tanhf +declare double %tanhl(double) ;; __builtin_tanhl +declare double %tanl(double) ;; __builtin_tanl +declare double %tgamma(double) ;; __builtin_tgamma +declare float %tgammaf(float) ;; __builtin_tgammaf +declare double %tgammal(double) ;; __builtin_tgammal +declare double %trunc(double) ;; __builtin_trunc +declare float %truncf(float) ;; __builtin_truncf +declare double %truncl(double) ;; __builtin_truncl +declare double %y0(double) ;; __builtin_y0 +declare float %y0f(float) ;; __builtin_y0f +declare double %y0l(double) ;; __builtin_y0l +declare double %y1(double) ;; __builtin_y1 +declare float %y1f(float) ;; __builtin_y1f +declare double %y1l(double) ;; __builtin_y1l +declare double %yn(int,double) ;; __builtin_yn +declare float %ynf(int,float) ;; __builtin_ynf +declare double %ynl(int,double) ;; __builtin_ynl +declare double %cabs(double,double) ;; __builtin_cabs +declare float %cabsf(float,float) ;; __builtin_cabsf +declare double %cabsl(double,double) ;; __builtin_cabsl +declare void %cacos("complex double"*,double,double) ;; __builtin_cacos +declare void %cacosf("complex float"*,float,float) ;; __builtin_cacosf +declare void %cacosh("complex double"*,double,double) ;; __builtin_cacosh +declare void %cacoshf("complex float"*,float,float) ;; __builtin_cacoshf +declare void %cacoshl("complex long double"*,double,double) ;; __builtin_cacoshl +declare void %cacosl("complex long double"*,double,double) ;; __builtin_cacosl +declare double %carg(double,double) ;; __builtin_carg +declare float %cargf(float,float) ;; __builtin_cargf +declare double %cargl(double,double) ;; __builtin_cargl +declare void %casin("complex double"*,double,double) ;; __builtin_casin +declare void %casinf("complex float"*,float,float) ;; __builtin_casinf +declare void %casinh("complex double"*,double,double) ;; __builtin_casinh +declare void %casinhf("complex float"*,float,float) ;; __builtin_casinhf +declare void %casinhl("complex long double"*,double,double) ;; __builtin_casinhl +declare void %casinl("complex long double"*,double,double) ;; __builtin_casinl +declare void %catan("complex double"*,double,double) ;; __builtin_catan +declare void %catanf("complex float"*,float,float) ;; __builtin_catanf +declare void %catanh("complex double"*,double,double) ;; __builtin_catanh +declare void %catanhf("complex float"*,float,float) ;; __builtin_catanhf +declare void %catanhl("complex long double"*,double,double) ;; __builtin_catanhl +declare void %catanl("complex long double"*,double,double) ;; __builtin_catanl +declare void %ccos("complex double"*,double,double) ;; __builtin_ccos +declare void %ccosf("complex float"*,float,float) ;; __builtin_ccosf +declare void %ccosh("complex double"*,double,double) ;; __builtin_ccosh +declare void %ccoshf("complex float"*,float,float) ;; __builtin_ccoshf +declare void %ccoshl("complex long double"*,double,double) ;; __builtin_ccoshl +declare void %ccosl("complex long double"*,double,double) ;; __builtin_ccosl +declare void %cexp("complex double"*,double,double) ;; __builtin_cexp +declare void %cexpf("complex float"*,float,float) ;; __builtin_cexpf +declare void %cexpl("complex long double"*,double,double) ;; __builtin_cexpl +declare double %cimag(double,double) ;; __builtin_cimag +declare float %cimagf(float,float) ;; __builtin_cimagf +declare double %cimagl(double,double) ;; __builtin_cimagl +declare void %conj("complex double"*,double,double) ;; __builtin_conj +declare void %conjf("complex float"*,float,float) ;; __builtin_conjf +declare void %conjl("complex long double"*,double,double) ;; __builtin_conjl +declare void %cpow("complex double"*,double,double,double,double) ;; __builtin_cpow +declare void %cpowf("complex float"*,float,float,float,float) ;; __builtin_cpowf +declare void %cpowl("complex long double"*,double,double,double,double) ;; __builtin_cpowl +declare void %cproj("complex double"*,double,double) ;; __builtin_cproj +declare void %cprojf("complex float"*,float,float) ;; __builtin_cprojf +declare void %cprojl("complex long double"*,double,double) ;; __builtin_cprojl +declare double %creal(double,double) ;; __builtin_creal +declare float %crealf(float,float) ;; __builtin_crealf +declare double %creall(double,double) ;; __builtin_creall +declare void %csin("complex double"*,double,double) ;; __builtin_csin +declare void %csinf("complex float"*,float,float) ;; __builtin_csinf +declare void %csinh("complex double"*,double,double) ;; __builtin_csinh +declare void %csinhf("complex float"*,float,float) ;; __builtin_csinhf +declare void %csinhl("complex long double"*,double,double) ;; __builtin_csinhl +declare void %csinl("complex long double"*,double,double) ;; __builtin_csinl +declare void %csqrt("complex double"*,double,double) ;; __builtin_csqrt +declare void %csqrtf("complex float"*,float,float) ;; __builtin_csqrtf +declare void %csqrtl("complex long double"*,double,double) ;; __builtin_csqrtl +declare void %ctan("complex double"*,double,double) ;; __builtin_ctan +declare void %ctanf("complex float"*,float,float) ;; __builtin_ctanf +declare void %ctanh("complex double"*,double,double) ;; __builtin_ctanh +declare void %ctanhf("complex float"*,float,float) ;; __builtin_ctanhf +declare void %ctanhl("complex long double"*,double,double) ;; __builtin_ctanhl +declare void %ctanl("complex long double"*,double,double) ;; __builtin_ctanl +declare int %bcmp(sbyte*,sbyte*,uint) ;; __builtin_bcmp +declare void %bcopy(sbyte*,sbyte*,uint) ;; __builtin_bcopy +declare void %bzero(sbyte*,uint) ;; __builtin_bzero +declare int %ffs(int) ;; __builtin_ffs +declare int %ffsl(int) ;; __builtin_ffsl +declare int %ffsll(long) ;; __builtin_ffsll +declare sbyte* %index(sbyte*,int) ;; __builtin_index +declare int %memcmp(sbyte*,sbyte*,uint) ;; __builtin_memcmp +declare sbyte* %memcpy(sbyte*,sbyte*,uint) ;; __builtin_memcpy +declare sbyte* %memmove(sbyte*,sbyte*,uint) ;; __builtin_memmove +declare sbyte* %mempcpy(sbyte*,sbyte*,uint) ;; __builtin_mempcpy +declare sbyte* %memset(sbyte*,int,uint) ;; __builtin_memset +declare sbyte* %rindex(sbyte*,int) ;; __builtin_rindex +declare sbyte* %stpcpy(sbyte*,sbyte*) ;; __builtin_stpcpy +declare sbyte* %strcat(sbyte*,sbyte*) ;; __builtin_strcat +declare sbyte* %strchr(sbyte*,int) ;; __builtin_strchr +declare int %strcmp(sbyte*,sbyte*) ;; __builtin_strcmp +declare sbyte* %strcpy(sbyte*,sbyte*) ;; __builtin_strcpy +declare uint %strcspn(sbyte*,sbyte*) ;; __builtin_strcspn +declare sbyte* %strdup(sbyte*) ;; __builtin_strdup +declare uint %strlen(sbyte*) ;; __builtin_strlen +declare sbyte* %strncat(sbyte*,sbyte*,uint) ;; __builtin_strncat +declare int %strncmp(sbyte*,sbyte*,uint) ;; __builtin_strncmp +declare sbyte* %strncpy(sbyte*,sbyte*,uint) ;; __builtin_strncpy +declare sbyte* %strpbrk(sbyte*,sbyte*) ;; __builtin_strpbrk +declare sbyte* %strrchr(sbyte*,int) ;; __builtin_strrchr +declare uint %strspn(sbyte*,sbyte*) ;; __builtin_strspn +declare sbyte* %strstr(sbyte*,sbyte*) ;; __builtin_strstr +declare int %fprintf(sbyte*,sbyte*, ...) ;; __builtin_fprintf +declare int %fprintf_unlocked(sbyte*,sbyte*, ...) ;; __builtin_fprintf_unlocked +declare int %fputc(int,sbyte*) ;; __builtin_fputc +declare int %fputc_unlocked(int,sbyte*) ;; __builtin_fputc_unlocked +declare int %fputs(sbyte*,sbyte*) ;; __builtin_fputs +declare int %fputs_unlocked(sbyte*,sbyte*) ;; __builtin_fputs_unlocked +declare int %fscanf(sbyte*,sbyte*, ...) ;; __builtin_fscanf +declare uint %fwrite(sbyte*,uint,uint,sbyte*) ;; __builtin_fwrite +declare uint %fwrite_unlocked(sbyte*,uint,uint,sbyte*) ;; __builtin_fwrite_unlocked +declare int %printf(sbyte*, ...) ;; __builtin_printf +declare int %printf_unlocked(sbyte*, ...) ;; __builtin_printf_unlocked +declare int %putchar(int) ;; __builtin_putchar +declare int %putchar_unlocked(int) ;; __builtin_putchar_unlocked +declare int %puts(sbyte*) ;; __builtin_puts +declare int %puts_unlocked(sbyte*) ;; __builtin_puts_unlocked +declare int %scanf(sbyte*, ...) ;; __builtin_scanf +declare int %snprintf(sbyte*,uint,sbyte*, ...) ;; __builtin_snprintf +declare int %sprintf(sbyte*,sbyte*, ...) ;; __builtin_sprintf +declare int %sscanf(sbyte*,sbyte*, ...) ;; __builtin_sscanf +declare int %vfprintf(sbyte*,sbyte*,sbyte*) ;; __builtin_vfprintf +declare int %vfscanf(sbyte*,sbyte*,sbyte*) ;; __builtin_vfscanf +declare int %vprintf(sbyte*,sbyte*) ;; __builtin_vprintf +declare int %vscanf(sbyte*,sbyte*) ;; __builtin_vscanf +declare int %vsnprintf(sbyte*,uint,sbyte*,sbyte*) ;; __builtin_vsnprintf +declare int %vsprintf(sbyte*,sbyte*,sbyte*) ;; __builtin_vsprintf +declare int %vsscanf(sbyte*,sbyte*,sbyte*) ;; __builtin_vsscanf +declare void %abort() ;; __builtin_abort +declare int %abs(int) ;; __builtin_abs +declare sbyte* %__builtin_aggregate_incoming_address(...) +declare sbyte* %alloca(uint) ;; __builtin_alloca +declare sbyte* %__builtin_apply(void (...)*,sbyte*,uint) +declare sbyte* %__builtin_apply_args(...) +declare int %__builtin_args_info(int) +declare sbyte* %calloc(uint,uint) ;; __builtin_calloc +declare int %__builtin_classify_type(...) +declare int %__builtin_clz(int) +declare int %__builtin_clzl(int) +declare int %__builtin_clzll(long) +declare int %__builtin_constant_p(...) +declare int %__builtin_ctz(int) +declare int %__builtin_ctzl(int) +declare int %__builtin_ctzll(long) +declare sbyte* %dcgettext(sbyte*,sbyte*,int) ;; __builtin_dcgettext +declare sbyte* %dgettext(sbyte*,sbyte*) ;; __builtin_dgettext +declare sbyte* %__builtin_dwarf_cfa() +declare uint %__builtin_dwarf_sp_column() +declare void %__builtin_eh_return(int,sbyte*) +declare int %__builtin_eh_return_data_regno(int) +declare void %exit(int) ;; __builtin_exit +declare int %__builtin_expect(int,int) +declare sbyte* %__builtin_extract_return_addr(sbyte*) +declare sbyte* %__builtin_frame_address(uint) +declare sbyte* %__builtin_frob_return_addr(sbyte*) +declare sbyte* %gettext(sbyte*) ;; __builtin_gettext +declare long %imaxabs(long) ;; __builtin_imaxabs +declare void %__builtin_init_dwarf_reg_size_table(sbyte*) +declare int %__builtin_isgreater(...) +declare int %__builtin_isgreaterequal(...) +declare int %__builtin_isless(...) +declare int %__builtin_islessequal(...) +declare int %__builtin_islessgreater(...) +declare int %__builtin_isunordered(...) +declare int %labs(int) ;; __builtin_labs +declare long %llabs(long) ;; __builtin_llabs +declare void %__builtin_longjmp(sbyte*,int) +declare sbyte* %malloc(uint) ;; __builtin_malloc +declare sbyte* %__builtin_next_arg(...) +declare int %__builtin_parity(int) +declare int %__builtin_parityl(int) +declare int %__builtin_parityll(long) +declare int %__builtin_popcount(int) +declare int %__builtin_popcountl(int) +declare int %__builtin_popcountll(long) +declare void %__builtin_prefetch(sbyte*, ...) +declare void %__builtin_return(sbyte*) +declare sbyte* %__builtin_return_address(uint) +declare sbyte* %__builtin_saveregs(...) +declare int %__builtin_setjmp(sbyte*) +declare void %__builtin_stdarg_start(sbyte**, ...) +declare int %strfmon(sbyte*,uint,sbyte*, ...) ;; __builtin_strfmon +declare uint %strftime(sbyte*,uint,sbyte*,sbyte*) ;; __builtin_strftime +declare void %__builtin_trap() +declare void %__builtin_unwind_init() +declare void %__builtin_va_copy(sbyte**,sbyte*) +declare void %__builtin_va_end(sbyte**) +declare void %__builtin_va_start(sbyte**, ...) +declare void %_exit(int) ;; __builtin__exit +declare void %_Exit(int) ;; __builtin__Exit + +sbyte* %gethellostr() { +entry: + %result = alloca sbyte* ; ty=sbyte** + store sbyte* getelementptr ([13 x sbyte]* %.str_1, int 0, int 0), sbyte** %result + br label %return +after_ret: + br label %return +return: + %tmp.1 = load sbyte** %result ; ty=sbyte* + ret sbyte* %tmp.1 +} + + +int %hello() { +entry: + %result = alloca int ; ty=int* + %tmp.2 = call sbyte* (...)* cast (sbyte* ()* %gethellostr to sbyte* (...)*)() ; ty=sbyte* + %tmp.0 = call int (sbyte*, ...)* %printf(sbyte* %tmp.2) ; ty=int + store int 0, int* %result + br label %return +after_ret: + br label %return +return: + %tmp.3 = load int* %result ; ty=int + ret int %tmp.3 +} + +;; Created by "GCC: (GNU) 3.4-llvm 20051104 (LLVM 1.6)" Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Wed Mar 1 01:31:52 2006 @@ -1,9 +1,40 @@ from pypy.translator.llvm.buildllvm import llvm_is_on_path if not llvm_is_on_path(): py.test.skip("llvm not found") - +import py from pypy.translator.llvm.pyllvm import pyllvm -def test_execution_context(): - code = open("hello.s").read() - pyllvm.start_ee("modname", code) +def test_execution_engine(): + ee = pyllvm.get_ee() + ee = pyllvm.get_ee() + ee = pyllvm.get_ee() + pyllvm.delete_ee() + ee2 = pyllvm.get_ee() + ee2 = pyllvm.get_ee() + ee2 = pyllvm.get_ee() + +def get_fresh_ee(): + pyllvm.delete_ee() + return pyllvm.get_ee() + +codepath = py.path.local(__file__).dirpath() + +def test_load(): + ee = get_fresh_ee() + ee.parse(codepath.join("hello.s").read()) + ee.parse(codepath.join("addnumbers.s").read()) + +def test_functions(): + ee = get_fresh_ee() + ee.parse(codepath.join("hello.s").read()) + ee.functions() + +def test_call1(): + ee = get_fresh_ee() + ee.parse(codepath.join("hello.s").read()) + ee.call_noargs("hello") + ee.call_noargs("gethellostr") + try: + ee.call_noargs("gethellostrx") + except: + pass From micktwomey at codespeak.net Wed Mar 1 01:37:29 2006 From: micktwomey at codespeak.net (micktwomey at codespeak.net) Date: Wed, 1 Mar 2006 01:37:29 +0100 (CET) Subject: [pypy-svn] r23799 - in pypy/dist/pypy/rpython: . rctypes rctypes/test test Message-ID: <20060301003729.C6B551007D@code0.codespeak.net> Author: micktwomey Date: Wed Mar 1 01:37:20 2006 New Revision: 23799 Added: pypy/dist/pypy/rpython/rctypes/rarray.py Modified: pypy/dist/pypy/rpython/extregistry.py pypy/dist/pypy/rpython/rctypes/implementation.py pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py pypy/dist/pypy/rpython/test/test_extregistry.py Log: (arigo, micktwomey, goden) Added get_repr support to the extregistry Implemented rctypes ARRAY support using the extregistry and get_repr. Added a register_type call for each primitive in rctypes.implementation which needs to be updated with the correct repr for each one. Modified: pypy/dist/pypy/rpython/extregistry.py ============================================================================== --- pypy/dist/pypy/rpython/extregistry.py (original) +++ pypy/dist/pypy/rpython/extregistry.py Wed Mar 1 01:37:20 2006 @@ -11,9 +11,10 @@ return annmodel.SomeBuiltin(self.compute_result_annotation, methodname=func.__name__) class ExtRegistryInstance(object): - def __init__(self, compute_annotation, specialize_call): + def __init__(self, compute_annotation, specialize_call, get_repr): self.compute_annotation = compute_annotation self.specialize_call = specialize_call + self.get_repr = get_repr def get_annotation(self, type, instance=None): return self.compute_annotation(type, instance) @@ -32,13 +33,14 @@ return annotation def create_entry(compute_result_annotation=None, compute_annotation=None, - specialize_call=None): + specialize_call=None, get_repr=None): if compute_result_annotation is not None: compute_result_annotation = create_annotation_callable( compute_result_annotation) return ExtRegistryFunc(compute_result_annotation, specialize_call) else: - return ExtRegistryInstance(compute_annotation, specialize_call) + return ExtRegistryInstance(compute_annotation, specialize_call, + get_repr) def register_value(value, **kwargs): EXT_REGISTRY_BY_VALUE[value] = create_entry(**kwargs) Modified: pypy/dist/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/implementation.py (original) +++ pypy/dist/pypy/rpython/rctypes/implementation.py Wed Mar 1 01:37:20 2006 @@ -17,9 +17,12 @@ from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst from pypy.rpython.error import TyperError from pypy.rpython.extregistry import register_value, register_metatype, \ - register_type + register_type, is_registered_type, lookup_type from pypy.annotation.pairtype import pairtype +from pypy.rpython import rint +# Importing for side effect of registering types with extregistry +import pypy.rpython.rctypes.rarray # ctypes_annotation_list contains various attributes that # are used by the pypy annotation. @@ -69,6 +72,9 @@ def do_register(the_type): register_value(the_type, compute_result_annotation=lambda s_arg: SomeCTypesObject(the_type)) + # XXX we need to register the correct repr for each primitive + register_type(the_type, + get_repr=lambda rtyper, s_primitive: rint.signed_repr) do_register(the_type) the_type.default_memorystate = SomeCTypesObject.NOMEMORY @@ -380,24 +386,11 @@ # answer.compute_result_annotation = classmethod(compute_result_annotation) # return answer -ArrayType = type(ARRAY(c_int, 10)) - -def arraytype_compute_annotation(metatype, type): - def compute_result_annotation(*arg_s): - return SomeCTypesObject(type, SomeCTypesObject.OWNSMEMORY) - return SomeBuiltin(compute_result_annotation, - methodname=type.__name__) - -register_type(ArrayType, - compute_annotation=arraytype_compute_annotation, - specialize_call=None) - class AbstractCtypesRepresentation( Repr ): """ The abstract base class of all ctypes low level representations. """ - class AbstractCtypesStructureRepresentation( AbstractCtypesRepresentation ): """ The abstract base class of ctypes structures' low level representation. @@ -505,6 +498,9 @@ class __extend__( SomeCTypesObject ): def rtyper_makerepr( self, rtyper ): + if is_registered_type(self.knowntype): + entry = lookup_type(self.knowntype) + return entry.get_repr(rtyper, self) return self.knowntype.createLowLevelRepresentation( rtyper, self ) def rtyper_makekey( self ): Added: pypy/dist/pypy/rpython/rctypes/rarray.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/rarray.py Wed Mar 1 01:37:20 2006 @@ -0,0 +1,48 @@ +from ctypes import ARRAY, c_int +from pypy.annotation.model import SomeCTypesObject, SomeBuiltin +from pypy.rpython import extregistry +from pypy.rpython.rmodel import Repr +from pypy.rpython.lltypesystem import lltype + +ArrayType = type(ARRAY(c_int, 10)) + +def arraytype_compute_annotation(metatype, type): + def compute_result_annotation(*arg_s): + return SomeCTypesObject(type, SomeCTypesObject.OWNSMEMORY) + return SomeBuiltin(compute_result_annotation, + methodname=type.__name__) + + +class ArrayRepr(Repr): + def __init__(self, rtyper, type): + + item_ctype = type._type_ + self.length = type._length_ + + entry = extregistry.lookup_type(item_ctype) + r_item = entry.get_repr(rtyper, item_ctype) + + self.lowleveltype = lltype.Ptr( + lltype.GcStruct( "CtypesGcArray_%s" % type.__name__, + ( "c_data", lltype.Array(r_item.lowleveltype, + hints={"nolength": True}) + ) + ) + ) + +def arraytype_specialize_call(hop): + r_array = hop.r_result + return hop.genop("malloc_varsize", [ + hop.inputconst(lltype.Void, r_array.lowleveltype.TO), + hop.inputconst(lltype.Signed, r_array.length), + ], resulttype=r_array.lowleveltype, + ) + +extregistry.register_type(ArrayType, + compute_annotation=arraytype_compute_annotation, + specialize_call=arraytype_specialize_call) + +def arraytype_get_repr(rtyper, s_array): + return ArrayRepr(rtyper, s_array.knowntype) + +extregistry.register_metatype(ArrayType, get_repr=arraytype_get_repr) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Wed Mar 1 01:37:20 2006 @@ -11,6 +11,7 @@ from pypy.annotation.model import SomeCTypesObject, SomeObject from pypy import conftest import sys +from pypy.rpython.test.test_llinterp import interpret thisdir = py.magic.autopath().dirpath() @@ -430,7 +431,8 @@ def test_specialize_pointer_to_struct(self): t = self.test_annotate_pointer_to_struct() t.buildrtyper().specialize() - #d#t.view() + if conftest.option.view: + t.view() def x_test_compile_pointer_to_struct(self): fn = compile( py_testfunc_struct_pointer_id, [ oppoint_type ] ) @@ -528,3 +530,10 @@ py.test.raises(IndexError, "s = a.build_types(py_test_annotate_array_content_index_error_on_negative_index,[])") + def test_specialize_array(self): + res = interpret(py_test_annotate_array, []) + c_data = res.c_data + assert c_data[0] == 0 + assert c_data[9] == 0 + py.test.raises(IndexError, "c_data[10]") + py.test.raises(TypeError, "len(c_data)") Modified: pypy/dist/pypy/rpython/test/test_extregistry.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_extregistry.py (original) +++ pypy/dist/pypy/rpython/test/test_extregistry.py Wed Mar 1 01:37:20 2006 @@ -5,11 +5,13 @@ from pypy.rpython.extregistry import EXT_REGISTRY_BY_VALUE, EXT_REGISTRY_BY_TYPE from pypy.rpython.extregistry import register_value, register_type from pypy.rpython.extregistry import register_metatype +from pypy.rpython.extregistry import lookup_type from pypy.annotation import model as annmodel from pypy.annotation.annrpython import RPythonAnnotator from pypy.translator.translator import TranslationContext from pypy.rpython.lltypesystem import lltype from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.rmodel import Repr def dummy(): raiseNameError @@ -122,3 +124,43 @@ res = interpret(func, []) assert res == 42 + +def test_register_type_with_get_repr(): + class DummyClass(object): + pass + + class SomeDummyObject(annmodel.SomeObject): + def rtyper_makerepr(self, rtyper): + entry = lookup_type(self.knowntype) + return entry.get_repr(rtyper, self) + + def rtyper_makekey( self ): + return self.__class__, self.knowntype + + def get_annotation(type, instance=None): + assert type is DummyClass + dummy_object = SomeDummyObject() + dummy_object.knowntype = DummyClass + return dummy_object + + class DummyRepr(Repr): + lowleveltype = lltype.Signed + + def convert_const(self, value): + return 42 + + def get_repr(rtyper, s_instance): + return DummyRepr() + + register_type(DummyClass, compute_annotation=get_annotation, + get_repr=get_repr) + + dummy_class = DummyClass() + + def func(): + return dummy_class + + res = interpret(func, []) + + assert res == 42 + \ No newline at end of file From arigo at codespeak.net Wed Mar 1 01:48:38 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Mar 2006 01:48:38 +0100 (CET) Subject: [pypy-svn] r23802 - pypy/dist/pypy/translator/c Message-ID: <20060301004838.3398F10080@code0.codespeak.net> Author: arigo Date: Wed Mar 1 01:48:32 2006 New Revision: 23802 Modified: pypy/dist/pypy/translator/c/symboltable.py Log: debugging-symbol support for arrays that don't store their own length. Modified: pypy/dist/pypy/translator/c/symboltable.py ============================================================================== --- pypy/dist/pypy/translator/c/symboltable.py (original) +++ pypy/dist/pypy/translator/c/symboltable.py Wed Mar 1 01:48:32 2006 @@ -142,13 +142,18 @@ ARRAY = self._TYPE.TO if isinstance(ARRAY, Array): length_offset = self._nth_offset(0) + if length_offset == -1: + raise TypeError, "array has no stored length: %r" % (ARRAY,) return self._read(Signed, length_offset) raise TypeError, "not an array: %r" % (ARRAY,) def __getitem__(self, index): ARRAY = self._TYPE.TO if isinstance(ARRAY, Array): - if not (0 <= index < len(self)): + length_offset = self._nth_offset(0) + if length_offset == -1: + pass # just assume the access is within bounds + elif not (0 <= index < len(self)): raise IndexError("array index out of bounds") item0_offset = self._nth_offset(1) item1_offset = self._nth_offset(2) From goden at codespeak.net Wed Mar 1 01:52:36 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Wed, 1 Mar 2006 01:52:36 +0100 (CET) Subject: [pypy-svn] r23803 - in pypy/dist/pypy/rpython: rctypes test Message-ID: <20060301005236.70C2C1007F@code0.codespeak.net> Author: goden Date: Wed Mar 1 01:52:32 2006 New Revision: 23803 Modified: pypy/dist/pypy/rpython/rctypes/implementation.py pypy/dist/pypy/rpython/test/test_extregistry.py Log: - (arigo, micktwomey, goden) replaced "from pypy.rpython.extregistry import ..." with "from pypy.rpython import extregistry" Modified: pypy/dist/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/implementation.py (original) +++ pypy/dist/pypy/rpython/rctypes/implementation.py Wed Mar 1 01:52:32 2006 @@ -16,8 +16,7 @@ Void from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst from pypy.rpython.error import TyperError -from pypy.rpython.extregistry import register_value, register_metatype, \ - register_type, is_registered_type, lookup_type +from pypy.rpython import extregistry from pypy.annotation.pairtype import pairtype from pypy.rpython import rint @@ -70,10 +69,10 @@ # no 'wrap_arg'. This might change in the future #the_type.compute_result_annotation = classmethod(lambda cls, s_arg:SomeCTypesObject(cls)) def do_register(the_type): - register_value(the_type, + extregistry.register_value(the_type, compute_result_annotation=lambda s_arg: SomeCTypesObject(the_type)) # XXX we need to register the correct repr for each primitive - register_type(the_type, + extregistry.register_type(the_type, get_repr=lambda rtyper, s_primitive: rint.signed_repr) do_register(the_type) the_type.default_memorystate = SomeCTypesObject.NOMEMORY @@ -133,7 +132,7 @@ _callable=None, convert_params = convert_params ) -register_metatype(CFuncPtrType, +extregistry.register_metatype(CFuncPtrType, compute_annotation=cfuncptrtype_compute_annotation, specialize_call=cfuncptrtype_specialize_call) @@ -498,8 +497,8 @@ class __extend__( SomeCTypesObject ): def rtyper_makerepr( self, rtyper ): - if is_registered_type(self.knowntype): - entry = lookup_type(self.knowntype) + if extregistry.is_registered_type(self.knowntype): + entry = extregistry.lookup_type(self.knowntype) return entry.get_repr(rtyper, self) return self.knowntype.createLowLevelRepresentation( rtyper, self ) Modified: pypy/dist/pypy/rpython/test/test_extregistry.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_extregistry.py (original) +++ pypy/dist/pypy/rpython/test/test_extregistry.py Wed Mar 1 01:52:32 2006 @@ -2,10 +2,7 @@ ##py.test.skip('In progress at PyCon') -from pypy.rpython.extregistry import EXT_REGISTRY_BY_VALUE, EXT_REGISTRY_BY_TYPE -from pypy.rpython.extregistry import register_value, register_type -from pypy.rpython.extregistry import register_metatype -from pypy.rpython.extregistry import lookup_type +from pypy.rpython import extregistry from pypy.annotation import model as annmodel from pypy.annotation.annrpython import RPythonAnnotator from pypy.translator.translator import TranslationContext @@ -16,7 +13,8 @@ def dummy(): raiseNameError -register_value(dummy, compute_result_annotation=annmodel.SomeInteger()) +extregistry.register_value(dummy, + compute_result_annotation=annmodel.SomeInteger()) def test_call_dummy(): def func(): @@ -34,7 +32,8 @@ def return_annotation(): return annmodel.SomeInteger() - register_value(dummy2, compute_result_annotation=return_annotation) + extregistry.register_value(dummy2, + compute_result_annotation=return_annotation) def func(): x = dummy2() @@ -57,7 +56,7 @@ assert instance is dummy_type return annmodel.SomeInteger() - register_type(DummyType, compute_annotation=get_annotation) + extregistry.register_type(DummyType, compute_annotation=get_annotation) a = RPythonAnnotator() s = a.build_types(func, []) @@ -80,7 +79,7 @@ assert x is real_class return annmodel.SomeInteger() - register_metatype(MetaType, compute_annotation=get_annotation) + extregistry.register_metatype(MetaType, compute_annotation=get_annotation) a = RPythonAnnotator() s = a.build_types(func, []) @@ -101,7 +100,7 @@ assert x is None return annmodel.SomeInteger() - register_metatype(MetaType, compute_annotation=get_annotation) + extregistry.register_metatype(MetaType, compute_annotation=get_annotation) a = RPythonAnnotator() s = a.build_types(func, [RealClass]) @@ -114,7 +113,7 @@ def dummy_specialize(hop): return hop.inputconst(lltype.Signed, 42) - register_value(dummy_func, + extregistry.register_value(dummy_func, compute_result_annotation=annmodel.SomeInteger(), specialize_call=dummy_specialize) @@ -131,7 +130,7 @@ class SomeDummyObject(annmodel.SomeObject): def rtyper_makerepr(self, rtyper): - entry = lookup_type(self.knowntype) + entry = extregistry.lookup_type(self.knowntype) return entry.get_repr(rtyper, self) def rtyper_makekey( self ): @@ -152,7 +151,7 @@ def get_repr(rtyper, s_instance): return DummyRepr() - register_type(DummyClass, compute_annotation=get_annotation, + extregistry.register_type(DummyClass, compute_annotation=get_annotation, get_repr=get_repr) dummy_class = DummyClass() @@ -163,4 +162,4 @@ res = interpret(func, []) assert res == 42 - \ No newline at end of file + From nik at codespeak.net Wed Mar 1 01:57:47 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 01:57:47 +0100 (CET) Subject: [pypy-svn] r23804 - pypy/branch/rpython-ooclassattrs Message-ID: <20060301005747.06F5C1008B@code0.codespeak.net> Author: nik Date: Wed Mar 1 01:57:43 2006 New Revision: 23804 Added: pypy/branch/rpython-ooclassattrs/ - copied from r23803, pypy/dist/pypy/rpython/ Log: (nik, pedronis) creating a branch for further in-progress ootype work (class attributes) From nik at codespeak.net Wed Mar 1 01:59:53 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 01:59:53 +0100 (CET) Subject: [pypy-svn] r23805 - in pypy/branch/rpython-ooclassattrs: . lltypesystem ootypesystem ootypesystem/test Message-ID: <20060301005953.651561008B@code0.codespeak.net> Author: nik Date: Wed Mar 1 01:59:39 2006 New Revision: 23805 Modified: pypy/branch/rpython-ooclassattrs/lltypesystem/lltype.py pypy/branch/rpython-ooclassattrs/ootypesystem/ootype.py pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oopbc.py pypy/branch/rpython-ooclassattrs/rclass.py pypy/branch/rpython-ooclassattrs/rmodel.py Log: (pedronis, nik) work-in-progress class attributes for ootypesystem. Modified: pypy/branch/rpython-ooclassattrs/lltypesystem/lltype.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/lltypesystem/lltype.py (original) +++ pypy/branch/rpython-ooclassattrs/lltypesystem/lltype.py Wed Mar 1 01:59:39 2006 @@ -64,6 +64,8 @@ def __ne__(self, other): return not (self == other) + _is_compatible = __eq__ + def __hash__(self): # cannot use saferecursive() -- see test_lltype.test_hash(). # NB. the __cached_hash should neither be used nor updated @@ -1100,6 +1102,7 @@ return result def isCompatibleType(TYPE1, TYPE2): + return TYPE1._is_compatible(TYPE2) return TYPE1 == TYPE2 # mark type ADT methods Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/ootype.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/ootype.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/ootype.py Wed Mar 1 01:59:39 2006 @@ -1,12 +1,23 @@ from pypy.rpython.lltypesystem.lltype import LowLevelType, Signed, Unsigned, Float, Char -from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, Primitive -from pypy.rpython.lltypesystem.lltype import frozendict +from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \ + Primitive, isCompatibleType +from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType class OOType(LowLevelType): - pass + + def _is_compatible(TYPE1, TYPE2): + if TYPE1 == TYPE2: + return True + if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): + return isSubclass(TYPE1, TYPE2) + else: + return False class Class(OOType): - pass + + def _defl(self): + return nullruntimeclass + Class = Class() class Instance(OOType): @@ -170,7 +181,7 @@ def __setattr__(self, name, value): self.__getattr__(name) - if self._TYPE._field_type(name) != typeOf(value): + if not isCompatibleType(typeOf(value), self._TYPE._field_type(name)): raise TypeError("Expected type %r" % self._TYPE._field_type(name)) self.__dict__[name] = value @@ -333,14 +344,6 @@ c = c._superclass return None -def isCompatibleType(TYPE1, TYPE2): - if TYPE1 == TYPE2: - return True - if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): - return isSubclass(TYPE1, TYPE2) - else: - return False - def ooupcast(INSTANCE, instance): assert instanceof(instance, INSTANCE) return instance Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py Wed Mar 1 01:59:39 2006 @@ -40,7 +40,7 @@ v_obj, v_cls = hop.inputargs(instance_repr, class_repr) if isinstance(v_cls, Constant): - c_cls = hop.inputconst(ootype.Void, v_cls.value._INSTANCE) + c_cls = hop.inputconst(ootype.Void, v_cls.value.class_._INSTANCE) return hop.genop('instanceof', [v_obj, c_cls], resulttype=ootype.Bool) else: raise TyperError("XXX missing impl of isinstance(x, variable)") Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py Wed Mar 1 01:59:39 2006 @@ -8,24 +8,122 @@ from pypy.annotation.pairtype import pairtype from pypy.tool.sourcetools import func_with_new_name -CLASSTYPE = ootype.Class +CLASSTYPE = ootype.Instance("Object_meta", ootype.ROOT, + fields={"class_": ootype.Class}) +OBJECT = ootype.Instance("Object", ootype.ROOT, + fields={'meta': CLASSTYPE}) + class ClassRepr(AbstractClassRepr): def __init__(self, rtyper, classdef): AbstractClassRepr.__init__(self, rtyper, classdef) - self.lowleveltype = ootype.Class + if self.classdef is not None: + self.rbase = getclassrepr(self.rtyper, self.classdef.basedef) + base_type = self.rbase.lowleveltype + self.lowleveltype = ootype.Instance( + self.classdef.name + "_meta", base_type) + else: + # we are ROOT + self.lowleveltype = CLASSTYPE def _setup_repr(self): - pass # not actually needed? + clsfields = {} + pbcfields = {} + if self.classdef is not None: + # class attributes + llfields = [] + """ + attrs = self.classdef.attrs.items() + attrs.sort() + for name, attrdef in attrs: + if attrdef.readonly: + s_value = attrdef.s_value + s_unboundmethod = self.prepare_method(s_value) + if s_unboundmethod is not None: + allmethods[name] = True + s_value = s_unboundmethod + r = self.rtyper.getrepr(s_value) + mangled_name = 'cls_' + name + clsfields[name] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + """ + # attributes showing up in getattrs done on the class as a PBC + extra_access_sets = self.rtyper.class_pbc_attributes.get( + self.classdef, {}) + for access_set, counter in extra_access_sets.items(): + for attr, s_value in access_set.attrs.items(): + r = self.rtyper.getrepr(s_value) + mangled_name = mangle('pbc%d' % counter, attr) + pbcfields[access_set, attr] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + + self.rbase.setup() + ootype.addFields(self.lowleveltype, dict(llfields)) + #self.clsfields = clsfields + self.pbcfields = pbcfields + self.meta_instance = None + + def get_meta_instance(self, cast_to_root_meta=True): + if self.meta_instance is None: + self.meta_instance = ootype.new(self.lowleveltype) + self.setup_meta_instance(self.meta_instance, self) + + meta_instance = self.meta_instance + if cast_to_root_meta: + meta_instance = ootype.ooupcast(CLASSTYPE, meta_instance) + return meta_instance - def getruntime(self): - return getinstancerepr(self.rtyper, self.classdef).lowleveltype._class + def setup_meta_instance(self, meta_instance, rsubcls): + if self.classdef is None: + rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) + setattr(meta_instance, 'class_', rinstance.lowleveltype._class) + else: + # setup class attributes: for each attribute name at the level + # of 'self', look up its value in the subclass rsubcls + def assign(mangled_name, value): + if isinstance(value, Constant) and isinstance(value.value, staticmethod): + value = Constant(value.value.__get__(42)) # staticmethod => bare function + llvalue = r.convert_desc_or_const(value) + setattr(meta_instance, mangled_name, llvalue) + + #mro = list(rsubcls.classdef.getmro()) + #for fldname in self.clsfields: + # mangled_name, r = self.clsfields[fldname] + # if r.lowleveltype is Void: + # continue + # value = rsubcls.classdef.classdesc.read_attribute(fldname, None) + # if value is not None: + # assign(mangled_name, value) + # extra PBC attributes + for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): + if rsubcls.classdef.classdesc not in access_set.descs: + continue # only for the classes in the same pbc access set + if r.lowleveltype is Void: + continue + attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) + if attrvalue is not None: + assign(mangled_name, attrvalue) + + # then initialize the 'super' portion of the vtable + meta_instance_super = ootype.ooupcast( + self.rbase.lowleveltype, meta_instance) + self.rbase.setup_meta_instance(meta_instance_super, rsubcls) + + getruntime = get_meta_instance + + #def getruntime(self): + # return getinstancerepr(self.rtyper, self.classdef).lowleveltype._class def rtype_issubtype(self, hop): class_repr = get_type_repr(self.rtyper) - vlist = hop.inputargs(class_repr, class_repr) - return hop.genop('subclassof', vlist, resulttype=ootype.Bool) + vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) + return hop.gendirectcall(ll_issubtype, vmeta1, vmeta2) + +def ll_issubtype(meta1, meta2): + class1 = meta1.class_ + class2 = meta2.class_ + return ootype.subclassof(class1, class2) # ____________________________________________________________ @@ -45,14 +143,14 @@ self.baserepr = None if self.classdef is None: - self.lowleveltype = ootype.ROOT + self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: - b = ootype.ROOT + b = OBJECT self.lowleveltype = ootype.Instance(classdef.shortname, b, {}, {}) self.prebuiltinstances = {} # { id(x): (x, _ptr) } @@ -259,7 +357,8 @@ if hop.args_s[0].can_be_none(): return hop.gendirectcall(ll_inst_type, vinst) else: - return hop.genop('classof', [vinst], resulttype=ootype.Class) + cmeta = inputconst(ootype.Void, "meta") + return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE) def rtype_hash(self, hop): if self.classdef is None: @@ -305,15 +404,23 @@ def new_instance(self, llops): """Build a new instance, without calling __init__.""" - - return llops.genop("new", + classrepr = getclassrepr(self.rtyper, self.classdef) + v_instance = llops.genop("new", [inputconst(ootype.Void, self.lowleveltype)], self.lowleveltype) - + cmeta = inputconst(ootype.Void, "meta") + cmeta_instance = inputconst(CLASSTYPE, classrepr.get_meta_instance()) + llops.genop("oosetfield", [v_instance, cmeta, cmeta_instance], + resulttype=ootype.Void) + return v_instance + def initialize_prebuilt_instance(self, value, result): # then add instance attributes from this level + classrepr = getclassrepr(self.rtyper, self.classdef) for mangled, (oot, default) in self.lowleveltype._allfields().items(): if oot is ootype.Void: llattrvalue = None + elif mangled == 'meta': + llattrvalue = classrepr.get_meta_instance() elif mangled == '_hash_cache_': # hash() support llattrvalue = hash(value) else: @@ -370,7 +477,7 @@ def ll_inst_type(obj): if obj: - return ootype.classof(obj) + return obj.meta else: # type(None) -> NULL (for now) - return ootype.nullruntimeclass + return ootype.null(CLASSTYPE) Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oopbc.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oopbc.py Wed Mar 1 01:59:39 2006 @@ -64,3 +64,20 @@ assert 3 == interpret(f1, [], type_system="ootype") assert 6 == interpret(f2, [], type_system="ootype") +def test_classes_attribute(): + class A: + a = 3 + class B(A): + a = 2 + def f(i): + if i == 1: + cls = B + else: + cls = A + instance = cls() + return cls.a + res = interpret(f, [0], type_system='ootype') + assert res == 3 + res = interpret(f, [1], type_system='ootype') + assert res == 2 + Modified: pypy/branch/rpython-ooclassattrs/rclass.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/rclass.py (original) +++ pypy/branch/rpython-ooclassattrs/rclass.py Wed Mar 1 01:59:39 2006 @@ -71,7 +71,7 @@ if self.classdef.commonbase(subclassdef) != self.classdef: raise TyperError("not a subclass of %r: %r" % ( self.classdef.name, desc)) - # + return getclassrepr(self.rtyper, subclassdef).getruntime() def convert_const(self, value): Modified: pypy/branch/rpython-ooclassattrs/rmodel.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/rmodel.py (original) +++ pypy/branch/rpython-ooclassattrs/rmodel.py Wed Mar 1 01:59:39 2006 @@ -4,7 +4,7 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem.lltype import \ Void, Bool, Float, Signed, Char, UniChar, \ - typeOf, LowLevelType, Ptr, PyObject + typeOf, LowLevelType, Ptr, PyObject, isCompatibleType from pypy.rpython.ootypesystem import ootype from pypy.rpython.error import TyperError, MissingRTypeOperation @@ -329,7 +329,7 @@ realtype = typeOf(value) except (AssertionError, AttributeError): realtype = '???' - if realtype != lltype: + if not isCompatibleType(realtype, lltype): raise TyperError("inputconst(reqtype = %s, value = %s):\n" "expected a %r,\n" " got a %r" % (reqtype, value, From arigo at codespeak.net Wed Mar 1 02:00:09 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Mar 2006 02:00:09 +0100 (CET) Subject: [pypy-svn] r23806 - in pypy/dist/pypy: doc/discussion lib rpython rpython/lltypesystem rpython/lltypesystem/test rpython/rctypes rpython/rctypes/test rpython/test translator/c/test Message-ID: <20060301010009.DE7C410080@code0.codespeak.net> Author: arigo Date: Wed Mar 1 01:59:42 2006 New Revision: 23806 Modified: pypy/dist/pypy/doc/discussion/removing-stable-compiler.txt (props changed) pypy/dist/pypy/lib/functional.py (props changed) pypy/dist/pypy/rpython/extregistry.py (props changed) pypy/dist/pypy/rpython/lltypesystem/lloperation.py (props changed) pypy/dist/pypy/rpython/lltypesystem/test/test_lloperation.py (props changed) pypy/dist/pypy/rpython/rctypes/rarray.py (props changed) pypy/dist/pypy/rpython/rctypes/test/ (props changed) pypy/dist/pypy/rpython/test/test_extregistry.py (props changed) pypy/dist/pypy/translator/c/test/test_symbolic.py (props changed) Log: fixeol From njriley at codespeak.net Wed Mar 1 02:06:23 2006 From: njriley at codespeak.net (njriley at codespeak.net) Date: Wed, 1 Mar 2006 02:06:23 +0100 (CET) Subject: [pypy-svn] r23807 - pypy/branch/njriley-trans/pypy/interpreter Message-ID: <20060301010623.A46BB10080@code0.codespeak.net> Author: njriley Date: Wed Mar 1 02:06:17 2006 New Revision: 23807 Modified: pypy/branch/njriley-trans/pypy/interpreter/executioncontext.py Log: Make TSC (single-threaded) transaction-safe. Modified: pypy/branch/njriley-trans/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/executioncontext.py Wed Mar 1 02:06:17 2006 @@ -71,12 +71,10 @@ opcode = code is None and 0 or ord(code.co_code[frame.next_instr]) s = 'tid=%d opcode=%d t=%d inst=%d\n' % \ (get_ident(), opcode, int(self.ticked), read_diff()) - if self.trans: - rtrans.end() + # if per-bytecode transactions enabled, this will function + # as an automatic transaction end/begin os.write(2, s) - if self.trans: - rtrans.begin() - else: + if not self.trans: self.ticked = False reset_diff() elif self.trans: @@ -191,8 +189,8 @@ self.trans = False else: self.trans = True - rtrans.enable() self.space.threadlocals.GIL.release() + rtrans.enable() rtrans.begin() def call_tracing(self, w_func, w_args): From njriley at codespeak.net Wed Mar 1 02:08:57 2006 From: njriley at codespeak.net (njriley at codespeak.net) Date: Wed, 1 Mar 2006 02:08:57 +0100 (CET) Subject: [pypy-svn] r23808 - in pypy/branch/njriley-trans/pypy: lib module/trans rpython rpython/module translator/c translator/c/src Message-ID: <20060301010857.6CD3810080@code0.codespeak.net> Author: njriley Date: Wed Mar 1 02:08:56 2006 New Revision: 23808 Modified: pypy/branch/njriley-trans/pypy/lib/imp.py pypy/branch/njriley-trans/pypy/module/trans/__init__.py pypy/branch/njriley-trans/pypy/module/trans/interp_trans.py pypy/branch/njriley-trans/pypy/module/trans/rtrans.py pypy/branch/njriley-trans/pypy/rpython/extfunctable.py pypy/branch/njriley-trans/pypy/rpython/module/ll_trans.py pypy/branch/njriley-trans/pypy/translator/c/extfunc.py pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h Log: Add trans.is_active, wrapping magic instruction to query if we are in a transaction. Modified: pypy/branch/njriley-trans/pypy/lib/imp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/imp.py (original) +++ pypy/branch/njriley-trans/pypy/lib/imp.py Wed Mar 1 02:08:56 2006 @@ -160,6 +160,7 @@ else: del _please_provide_import_lock import thread + import trans class _ImportLock: def __init__(self): @@ -169,6 +170,8 @@ def held(self): """Return True if the import lock is currently held, else False.""" + if trans.is_active(): + return True return self.in_thread is not None def acquire(self): @@ -176,6 +179,8 @@ This lock should be used by import hooks to ensure thread-safety when importing modules. """ + if trans.is_active(): + return myident = thread.get_ident() if self.in_thread == myident: self.recursions += 1 @@ -186,6 +191,8 @@ def release(self): """Release the interpreter's import lock.""" + if trans.is_active(): + return myident = thread.get_ident() if self.in_thread != myident: raise RuntimeError("not holding the import lock") Modified: pypy/branch/njriley-trans/pypy/module/trans/__init__.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/trans/__init__.py (original) +++ pypy/branch/njriley-trans/pypy/module/trans/__init__.py Wed Mar 1 02:08:56 2006 @@ -7,10 +7,11 @@ } interpleveldefs = { - 'begin' : 'interp_trans.begin', - 'end' : 'interp_trans.end', - 'abort' : 'interp_trans.abort', - 'pause' : 'interp_trans.pause', - 'unpause' : 'interp_trans.unpause', - 'verbose' : 'interp_trans.verbose', + 'begin' : 'interp_trans.begin', + 'end' : 'interp_trans.end', + 'abort' : 'interp_trans.abort', + 'pause' : 'interp_trans.pause', + 'unpause' : 'interp_trans.unpause', + 'verbose' : 'interp_trans.verbose', + 'is_active' : 'interp_trans.is_active', } Modified: pypy/branch/njriley-trans/pypy/module/trans/interp_trans.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/trans/interp_trans.py (original) +++ pypy/branch/njriley-trans/pypy/module/trans/interp_trans.py Wed Mar 1 02:08:56 2006 @@ -25,3 +25,6 @@ def verbose(space): rtrans.verbose() return space.w_None + +def is_active(space): + return space.wrap(rtrans.is_active()) Modified: pypy/branch/njriley-trans/pypy/module/trans/rtrans.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/trans/rtrans.py (original) +++ pypy/branch/njriley-trans/pypy/module/trans/rtrans.py Wed Mar 1 02:08:56 2006 @@ -25,3 +25,7 @@ def disable(): os.write(2, '= rtrans.disable\n') + +def is_active(): + os.write(2, '= rtrans.is_active\n') + return False Modified: pypy/branch/njriley-trans/pypy/rpython/extfunctable.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/extfunctable.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/extfunctable.py Wed Mar 1 02:08:56 2006 @@ -250,6 +250,7 @@ declare(rtrans.verbose, noneannotation, 'll_trans/verbose') declare(rtrans.enable, noneannotation, 'll_trans/enable') declare(rtrans.disable, noneannotation, 'll_trans/disable') +declare(rtrans.is_active, bool, 'll_trans/is_active') # ___________________________________________________________ # javascript Modified: pypy/branch/njriley-trans/pypy/rpython/module/ll_trans.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/module/ll_trans.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/module/ll_trans.py Wed Mar 1 02:08:56 2006 @@ -29,3 +29,7 @@ def ll_trans_disable(): pass ll_trans_disable.suggested_primitive = True + +def ll_trans_is_active(): + return False +ll_trans_is_active.suggested_primitive = True Modified: pypy/branch/njriley-trans/pypy/translator/c/extfunc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/extfunc.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/extfunc.py Wed Mar 1 02:08:56 2006 @@ -63,6 +63,7 @@ ll_trans.ll_trans_verbose: 'LL_trans_verbose', ll_trans.ll_trans_enable: 'LL_trans_enable', ll_trans.ll_trans_disable: 'LL_trans_disable', + ll_trans.ll_trans_is_active: 'LL_trans_is_active', ll_tsc.ll_tsc_read: 'LL_tsc_read', ll_tsc.ll_tsc_read_diff: 'LL_tsc_read_diff', ll_tsc.ll_tsc_reset_diff:'LL_tsc_reset_diff', Modified: pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h Wed Mar 1 02:08:56 2006 @@ -103,4 +103,15 @@ set_auto_xact(0); } +int +LL_trans_is_active(void) +{ + int ret_val; + + XACT_ACTIVE(ret_val); + assert(ret_val == 0 || ret_val == 1); + + return ret_val; +} + #endif /* PYPY_NOT_MAIN_FILE */ From rxe at codespeak.net Wed Mar 1 02:58:23 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 02:58:23 +0100 (CET) Subject: [pypy-svn] r23812 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060301015823.C37441007F@code0.codespeak.net> Author: rxe Date: Wed Mar 1 02:58:20 2006 New Revision: 23812 Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: functions() now returns a tuple of function signatures (albeit in a only useful to llvm manner). Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Wed Mar 1 02:58:20 2006 @@ -82,20 +82,47 @@ return Py_None; } -static PyObject *ee_functions(PyExecutionEngine *self, PyObject *args) { - +static PyObject *ee_functions(PyExecutionEngine *self) { + int funccount = 0; Module::FunctionListType &fns = self->exec->getModule().getFunctionList(); + // spin thrru and get function count for (Module::FunctionListType::const_iterator ii = fns.begin(); ii != fns.end(); ++ii) { - if (ii->isIntrinsic() || ii->isExternal()) { - continue; + if (!(ii->isIntrinsic() || ii->isExternal())) { + funccount += 1; } - std::cout << ii->getReturnType()->getDescription() << " " << ii->getName() << std::endl; - std::cout << " -> " << ii->getFunctionType()->getDescription() << std::endl; - std::cout << std::endl; - } + } + + PyObject *functions = PyTuple_New(funccount); + + int count = 0; + for (Module::FunctionListType::const_iterator ii = fns.begin(); + ii != fns.end(); + ++ii, funccount++) { + if (!(ii->isIntrinsic() || ii->isExternal())) { + + unsigned argcount = ii->getFunctionType()->getNumParams(); + + PyObject *entry = PyTuple_New(3); + + PyObject *returnId = PyInt_FromLong(ii->getFunctionType()->getReturnType()->getTypeID()); + PyObject *name = PyString_FromString(ii->getName().c_str()); + PyObject *args = PyTuple_New(argcount); + + for (unsigned jj=0; jjgetFunctionType()->getParamType(jj)->getTypeID(); + PyTuple_SetItem(args, (long) jj, PyInt_FromLong(argtype)); + } + + PyTuple_SetItem(entry, 0, returnId); + PyTuple_SetItem(entry, 1, name); + PyTuple_SetItem(entry, 2, args); + + PyTuple_SetItem(functions, count, entry); + count += 1; + } + } - Py_INCREF(Py_None); - return Py_None; + return functions; } static PyMethodDef ee_methodlist[] = { @@ -197,7 +224,7 @@ } static PyObject *pyllvm_delete_ee(PyObject *self, PyObject *args) { - PyExecutionEngine *ee = (PyExecutionEngine *) pyllvm_execution_engine; + PyExecutionEngine *ee = (PyExecutionEngine *) pyllvm_execution_engine; if (ee != NULL) { // bye Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Wed Mar 1 02:58:20 2006 @@ -27,7 +27,13 @@ def test_functions(): ee = get_fresh_ee() ee.parse(codepath.join("hello.s").read()) - ee.functions() + functions = ee.functions() + assert len(functions) == 2 + for ii in functions: + assert len(ii) == 3 + assert ii[0] > 0 + assert ii[1] in 'gethellostr', 'hello' + assert len(ii[2]) == 0 def test_call1(): ee = get_fresh_ee() From stuart at codespeak.net Wed Mar 1 03:09:42 2006 From: stuart at codespeak.net (stuart at codespeak.net) Date: Wed, 1 Mar 2006 03:09:42 +0100 (CET) Subject: [pypy-svn] r23813 - in pypy/dist: lib-python/modified-2.4.1 pypy/interpreter pypy/interpreter/astcompiler pypy/interpreter/pyparser pypy/interpreter/pyparser/data pypy/interpreter/pyparser/test pypy/interpreter/pyparser/test/samples pypy/interpreter/test Message-ID: <20060301020942.875371007D@code0.codespeak.net> Author: stuart Date: Wed Mar 1 03:09:41 2006 New Revision: 23813 Added: pypy/dist/lib-python/modified-2.4.1/opcode.py - copied, changed from r23743, pypy/dist/lib-python/2.4.1/opcode.py pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py Modified: pypy/dist/pypy/interpreter/astcompiler/ast.py pypy/dist/pypy/interpreter/astcompiler/ast.txt pypy/dist/pypy/interpreter/astcompiler/pyassem.py pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/pyparser/astbuilder.py pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a pypy/dist/pypy/interpreter/pyparser/pysymbol.py pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py pypy/dist/pypy/interpreter/pyparser/test/test_samples.py pypy/dist/pypy/interpreter/test/test_syntax.py Log: (Arre, Ale, Stuart Williams) Added with statement. Cleaned up code to no longer depend either on dis module for byte code opcodes or on Python 2.4. Missing: more tests and from __future__ import with_statement. Modified: pypy/dist/pypy/interpreter/astcompiler/ast.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/ast.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/ast.py Wed Mar 1 03:09:41 2006 @@ -4195,10 +4195,19 @@ def getChildren(self): "NOT_RPYTHON" - return self.expr, self.body, self.var + children = [] + children.append(self.expr) + children.append(self.body) + children.append(self.var) + return tuple(children) def getChildNodes(self): - return [self.expr, self.body] + nodelist = [] + nodelist.append(self.expr) + nodelist.append(self.body) + if self.var is not None: + nodelist.append(self.var) + return nodelist def __repr__(self): return "With(%s, %s, %s)" % (self.expr.__repr__(), self.body.__repr__(), self.var.__repr__()) @@ -4215,9 +4224,12 @@ def fset_body( space, self, w_arg): self.body = space.interp_w(Node, w_arg, can_be_None=False) def fget_var( space, self): - return space.wrap(self.var) + if self.var is None: + return space.w_None + else: + return space.wrap(self.var) def fset_var( space, self, w_arg): - self.var = space.str_w(w_arg) + self.var = space.interp_w(Node, w_arg, can_be_None=True) def descr_With_new(space, w_subtype, w_expr, w_body, w_var, lineno=-1): self = space.allocate_instance(With, w_subtype) @@ -4225,7 +4237,7 @@ self.expr = expr body = space.interp_w(Node, w_body, can_be_None=False) self.body = body - var = space.str_w(w_var) + var = space.interp_w(Node, w_var, can_be_None=True) self.var = var self.lineno = lineno return space.wrap(self) Modified: pypy/dist/pypy/interpreter/astcompiler/ast.txt ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/ast.txt (original) +++ pypy/dist/pypy/interpreter/astcompiler/ast.txt Wed Mar 1 03:09:41 2006 @@ -27,7 +27,7 @@ Break: Continue: For: assign, list, body, else_& -With: expr, body, var*str +With: expr, body, var& While: test, body, else_& If: tests!, else_& Exec: expr, locals&, globals& Modified: pypy/dist/pypy/interpreter/astcompiler/pyassem.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pyassem.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pyassem.py Wed Mar 1 03:09:41 2006 @@ -1,6 +1,5 @@ """A flow graph representation for Python bytecode""" -import dis import sys from pypy.interpreter.astcompiler import misc, ast @@ -9,7 +8,15 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.baseobjspace import W_Root +# load opcode.py as pythonopcode from our own lib +def load_opcode(): + import new, py + global pythonopcode + pythonopcode = new.module('opcode') + opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') + execfile(str(opcode_path), pythonopcode.__dict__) +load_opcode() class BlockSet: """A Set implementation specific to Blocks @@ -633,11 +640,11 @@ self.stage = FLAT hasjrel = {} - for i in dis.hasjrel: - hasjrel[dis.opname[i]] = True + for i in pythonopcode.hasjrel: + hasjrel[pythonopcode.opname[i]] = True hasjabs = {} - for i in dis.hasjabs: - hasjabs[dis.opname[i]] = True + for i in pythonopcode.hasjabs: + hasjabs[pythonopcode.opname[i]] = True def convertArgs(self): """Convert arguments from symbolic to concrete form""" @@ -772,7 +779,7 @@ index = self._lookupName(arg, self.closure) return InstrInt(inst.op, index) - _cmp = list(dis.cmp_op) + _cmp = list(pythonopcode.cmp_op) def _convert_COMPARE_OP(self, inst): assert isinstance(inst, InstrName) arg = inst.name @@ -817,8 +824,9 @@ self.stage = DONE opnum = {} - for num in range(len(dis.opname)): - opnum[dis.opname[num]] = num + for num in range(len(pythonopcode.opname)): + opnum[pythonopcode.opname[num]] = num + # This seems to duplicate dis.opmap from opcode.opmap del num def newCodeObject(self): @@ -1048,6 +1056,7 @@ 'SETUP_EXCEPT': 3, 'SETUP_FINALLY': 3, 'FOR_ITER': 1, + 'WITH_CLEANUP': 3, } # use pattern match patterns = [ Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Wed Mar 1 03:09:41 2006 @@ -543,6 +543,50 @@ self.nextBlock(end) + __with_count = 0 + + def visitWith(self, node): + node.expr.accept(self) + self.emitop('LOAD_ATTR', '__context__') + self.emitop_int('CALL_FUNCTION', 0) + self.emit('DUP_TOP') + + ## exit = ctx.__exit__ + self.emitop('LOAD_ATTR', '__exit__') + exit = "$exit%d" % self.__with_count + var = "$var%d" % self.__with_count + self.__with_count = self.__with_count + 1 + self._implicitNameOp('STORE', exit) + + self.emitop('LOAD_ATTR', '__enter__') + self.emitop_int('CALL_FUNCTION', 0) + finally_block = self.newBlock() + + if node.var is not None: # VAR is present + self._implicitNameOp('STORE', var) + self.emitop_block('SETUP_FINALLY', finally_block) + self._implicitNameOp('LOAD', var) + self._implicitNameOp('DELETE', var) + node.var.accept(self) + else: + self.emit('POP_TOP') + self.emitop_block('SETUP_FINALLY', finally_block) + + node.body.accept(self) + + self.emit('POP_BLOCK') + self.emitop_obj('LOAD_CONST', self.space.w_None) # WITH_CLEANUP checks for normal exit + self.nextBlock(finally_block) + + # find local variable with is context.__exit__ + self._implicitNameOp('LOAD', exit) + self._implicitNameOp('DELETE', exit) + + self.emit('WITH_CLEANUP') + self.emitop_int('CALL_FUNCTION', 3) + self.emit('POP_TOP') + self.emit('END_FINALLY') + def visitCompare(self, node): node.expr.accept( self ) cleanup = self.newBlock() Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Mar 1 03:09:41 2006 @@ -20,7 +20,7 @@ import new, py global pythonopcode pythonopcode = new.module('opcode') - opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/2.4.1/opcode.py') + opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') execfile(str(opcode_path), pythonopcode.__dict__) load_opcode() @@ -647,6 +647,25 @@ block = pyframe.FinallyBlock(f, f.next_instr + offsettoend) f.blockstack.push(block) + def WITH_CLEANUP(f): + x = f.valuestack.top() + u = f.valuestack.top(1) + if (f.space.is_w(f.space.type(u), f.space.w_int) + or f.space.is_w(u, f.space.w_None)): + u = v = w = f.space.w_None + else: + v = f.valuestack.top(2) + w = f.valuestack.top(3) + f.valuestack.pop() + f.valuestack.pop() + f.valuestack.pop() + f.valuestack.pop() + f.valuestack.push(f.space.w_None) + f.valuestack.push(x) + f.valuestack.push(u) + f.valuestack.push(v) + f.valuestack.push(w) + def call_function(f, oparg, w_star=None, w_starstar=None): n_arguments = oparg & 0xff n_keywords = (oparg>>8) & 0xff Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/astbuilder.py (original) +++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py Wed Mar 1 03:09:41 2006 @@ -1236,9 +1236,9 @@ else_ = atoms[6] builder.push(ast.While(test, body, else_, atoms[0].lineno)) - def build_with_stmt(builder, nb): - """with_stmt: 'with' test [ 'as' NAME ] ':' suite""" + """with_stmt: 'with' test [ NAME expr ] ':' suite""" + atoms = get_atoms(builder, nb) # skip 'with' test = atoms[1] @@ -1247,11 +1247,15 @@ var = None # if there is an "as" clause else: - var = atoms[3] + token = atoms[2] + assert isinstance(token, TokenObject) + if token.get_value() != 'as': + raise SyntaxError("invalid syntax", token.lineno, token.col) + varexpr = atoms[3] + var = to_lvalue(varexpr, consts.OP_ASSIGN) body = atoms[5] builder.push(ast.With(test, body, var, atoms[0].lineno)) - def build_import_name(builder, nb): """import_name: 'import' dotted_as_names @@ -1500,7 +1504,7 @@ sym['break_stmt'] : build_break_stmt, sym['for_stmt'] : build_for_stmt, sym['while_stmt'] : build_while_stmt, -# sym['with_stmt'] : build_with_stmt, + sym['with_stmt'] : build_with_stmt, sym['import_name'] : build_import_name, sym['import_from'] : build_import_from, sym['yield_stmt'] : build_yield_stmt, Modified: pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a (original) +++ pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a Wed Mar 1 03:09:41 2006 @@ -63,12 +63,13 @@ exec_stmt: 'exec' expr ['in' test [',' test]] assert_stmt: 'assert' test [',' test] -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite] for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite) +with_stmt: 'with' test [ NAME expr ] ':' suite # NB compile.c makes sure that the default except clause is last except_clause: 'except' [test [',' test]] suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT Modified: pypy/dist/pypy/interpreter/pyparser/pysymbol.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/pysymbol.py (original) +++ pypy/dist/pypy/interpreter/pyparser/pysymbol.py Wed Mar 1 03:09:41 2006 @@ -49,19 +49,6 @@ _cpython_symbols = SymbolMapper( symbol.sym_name ) - -### prepopulate symbol table from symbols used by CPython -##for _value, _name in _cpython_symbols.sym_name.items(): -## globals()[_name] = _value - - -### (This function does not seen to be called right now) -##def update_symbols( parser ): -## """Update the symbol module according to rules -## in PythonParser instance : parser""" -## for rule in parser.rules: -## _cpython_symbols.add_symbol( rule ) - # There is no symbol in this module until the grammar is loaded # once loaded the grammar parser will fill the mappings with the # grammar symbols Added: pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py Wed Mar 1 03:09:41 2006 @@ -0,0 +1,4 @@ +# EXPECT: Module(None, Stmt([With(Name('acontext'), Stmt([Pass()]), None)])) +with acontext: + pass + Added: pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py Wed Mar 1 03:09:41 2006 @@ -0,0 +1,4 @@ +# EXPECT: Module(None, Stmt([With(Name('acontext'), Stmt([Pass()]), AssName('avariable', OP_ASSIGN))])) +with acontext as avariable: + pass + Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py (original) +++ pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py Wed Mar 1 03:09:41 2006 @@ -745,8 +745,12 @@ for expr in family: yield check_expression, expr, 'exec' +NEW_GRAMMAR_SNIPPETS = [ + 'snippet_with_1.py', + 'snippet_with_2.py', + ] + SNIPPETS = [ -# 'snippet_with_1.py', 'snippet_1.py', 'snippet_several_statements.py', 'snippet_simple_function.py', @@ -788,7 +792,7 @@ ] def test_snippets(): - for snippet_name in SNIPPETS: + for snippet_name in SNIPPETS + NEW_GRAMMAR_SNIPPETS: filepath = os.path.join(os.path.dirname(__file__), 'samples', snippet_name) source = file(filepath).read() # To avoid using the stable compiler we pull an explicit AST out of the snippet Modified: pypy/dist/pypy/interpreter/pyparser/test/test_samples.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/test/test_samples.py (original) +++ pypy/dist/pypy/interpreter/pyparser/test/test_samples.py Wed Mar 1 03:09:41 2006 @@ -21,6 +21,10 @@ #"snippet_import_statements.py", "snippet_decorators.py", ] +SKIP_ALWAYS = [ + "snippet_with_1.py", + "snippet_with_2.py", +] REAL_EXPECTED_OUTPUT = { # for snippets that show bugs of Python's compiler package "snippet_transformer_bug.py": @@ -73,6 +77,8 @@ for fname in os.listdir(samples_dir): if not fname.endswith('.py'): continue + if fname in SKIP_ALWAYS: + continue if GRAMMAR_MISMATCH and fname in SKIP_IF_NOT_NATIVE: print "Skipping", fname continue Modified: pypy/dist/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_syntax.py (original) +++ pypy/dist/pypy/interpreter/test/test_syntax.py Wed Mar 1 03:09:41 2006 @@ -256,6 +256,30 @@ exec s assert x == expected +class AppTestWith: + def test_with(self): + + s = """if 1: + # from __future__ import with_statement + class Context: + def __init__(self): + self.calls = list() + def __context__(self): + self.calls.append('__context__') + return self + def __enter__(self): + self.calls.append('__enter__') + pass + def __exit__(self, exc_type, exc_value, exc_tb): + self.calls.append('__exit__') + pass + acontext = Context() + with acontext: + pass + """ + exec s + + assert acontext.calls == '__context__ __enter__ __exit__'.split() if __name__ == '__main__': # only to check on top of CPython (you need 2.4) From bea at codespeak.net Wed Mar 1 04:54:27 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Wed, 1 Mar 2006 04:54:27 +0100 (CET) Subject: [pypy-svn] r23819 - pypy/extradoc/planning Message-ID: <20060301035427.5E0841006D@code0.codespeak.net> Author: bea Date: Wed Mar 1 04:54:22 2006 New Revision: 23819 Modified: pypy/extradoc/planning/sprint-planning.txt Log: updated with the leysin sprint and louvain....please keep this document up to date Modified: pypy/extradoc/planning/sprint-planning.txt ============================================================================== --- pypy/extradoc/planning/sprint-planning.txt (original) +++ pypy/extradoc/planning/sprint-planning.txt Wed Mar 1 04:54:22 2006 @@ -24,18 +24,25 @@ Primary organizer: Holger and Michael -February/Europe +March/Europe ------------------- -Time & location: ? parallell with PyCon and PyCon sprint (24th February-1 March) -Brussels or Saarbruecken? +Time & location: Louvain-La-Neuve 6th-10th March -Nature: joint sprint with OZ community and Roel Wuyts/ULB attending ? -DFKI and Logilab primarily since other partners are sprinting -at PyCon and also do the Malaga conference. +Nature: joint sprint with OZ community and Roel Wuyts/ULB attending. +DFKI and Logilab primarily + Samuele, Carl F. Primary organizer: Nicolas Chauvat +April/Leysin +------------- + +Time & location: ?, Leysin, Switzerland + +Nature: closed/core + +Primary organizer: Armin + April/Tokyo ------------- From auc at codespeak.net Wed Mar 1 15:37:29 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 15:37:29 +0100 (CET) Subject: [pypy-svn] r23829 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301143729.BC8CF1007B@code0.codespeak.net> Author: auc Date: Wed Mar 1 15:37:27 2006 New Revision: 23829 Modified: pypy/dist/pypy/lib/logic/computation_space/constraint.py Log: bogus equality tests Modified: pypy/dist/pypy/lib/logic/computation_space/constraint.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/constraint.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/constraint.py Wed Mar 1 15:37:27 2006 @@ -125,6 +125,9 @@ def copy_to(self, space): return self.__class__(space, self._variables) + def __eq__(self, other): #FIXME and parent + if not isinstance(other, self.__class__): return False + return self._variables == other._variables class BasicConstraint(object): """A BasicConstraint, which is never queued by the Repository @@ -169,6 +172,8 @@ repr(self)) return 1 + def __eq__(self, other): + raise NotImplementedError def make_lambda_head(vars): var_ids = ','.join([var.name for var in vars]) @@ -268,6 +273,13 @@ return maybe_entailed + def __eq__(self, other): + if not super(Expression, self).__eq__(other): return False + r1 = self.formula == other.formula + r2 = self.type == other.type + return r1 and r2 + + def __repr__(self): return '<%s>' % self.formula From auc at codespeak.net Wed Mar 1 15:38:10 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 15:38:10 +0100 (CET) Subject: [pypy-svn] r23830 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301143810.58BA41007C@code0.codespeak.net> Author: auc Date: Wed Mar 1 15:38:07 2006 New Revision: 23830 Added: pypy/dist/pypy/lib/logic/computation_space/event.py Log: new event types to trigger propagation Added: pypy/dist/pypy/lib/logic/computation_space/event.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/computation_space/event.py Wed Mar 1 15:38:07 2006 @@ -0,0 +1,14 @@ +class NewSpace: pass + +class Clone: pass + +class Revise(object): + + def __init__(self, var): + self.var = var + + def __eq__(self, other): + if not isinstance(other, Distributed): return False + return self.var == other.var + + From auc at codespeak.net Wed Mar 1 15:39:57 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 15:39:57 +0100 (CET) Subject: [pypy-svn] r23831 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301143957.4E9DC1007E@code0.codespeak.net> Author: auc Date: Wed Mar 1 15:39:53 2006 New Revision: 23831 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: * event notification * ... Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 1 15:39:53 2006 @@ -16,16 +16,20 @@ from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor +import event # NewSpace, Clone, Revise -class Alternatives(object): +class Alternative(object): - def __init__(self, nb_alternatives): - self._nbalt = nb_alternatives + def __init__(self, choices): + self._choices = choices def __eq__(self, other): if other is None: return False - if not isinstance(other, Alternatives): return False - return self._nbalt == other._nbalt + if not isinstance(other, Alternative): return False + return self._choices == other._choices + + def __str__(self): + return "Alternatives(%s)" % self._choices def NoProblem(): """the empty problem, used by clone()""" @@ -76,22 +80,22 @@ def __init__(self, problem, parent=None): self.id = ComputationSpace._id_count ComputationSpace._id_count += 1 + self.status = Unknown # consistency-preserving stuff self.in_transaction = False self.bind_lock = RLock() self.var_lock = RLock() self.distributor = DefaultDistributor(self) - self.status = Unknown + # parent/children self.parent = parent self.children = set() - self.changelog = [] - self.domain_history = [] # mapping from domains to variables self.doms = {} # set of all constraints self.constraints = set() # mapping from vars to constraints self.var_const_map = {} + self.event_set = set() if parent is None: self.vars = set() @@ -100,8 +104,7 @@ self.root = self.var('__root__') # set up the problem self.bind(self.root, problem(self)) - self.changelog = [var for var in self.vars] - # check satisfiability of the space + self._notify(event.NewSpace) self._init_choose_commit() self.distributor.start() else: @@ -115,6 +118,7 @@ self.copy_constraints(parent) # ... self.status = Unknown + self._notify(event.Clone) self.distributor = parent.distributor.__class__(self) self._init_choose_commit() @@ -143,87 +147,56 @@ self.parent = None self.children = None self.CHOOSE.bind(0) + self.STABLE.bind(0) -## def __eq__(self, spc): -## """space equality defined as : -## * same set of vars with a domain -## * same name set -## * equal domains -## * same set of constraints -## * different propagators of the same type""" -## if id(self) == id(spc): return True -## r1 = self.vars == spc.vars -## r2 = self.names == spc.names -## r3 = self.constraints == spc.constraints -## r4 = self.distributor != spc.distributor -## r5 = self.root == spc.root -## if not r1 and r2 and r3 and r4 and r5: -## return False -## # now the domains -## it1 = [item for item in self.doms.items() -## if item[1] != NoDom] -## it2 = [item for item in spc.doms.items() -## if item[1] != NoDom] -## it1.sort() -## it2.sort() -## for (v1, d1), (v2, d2) in zip (it1, it2): -## ## if d1 != d2: -## ## print v1, d1 -## ## print v2, d2 -## ## else: -## ## print "%s.dom == %s.dom" % (v1, v2) -## if v1 != v2: return False -## if d1 != d2: return False -## if id(v1) != id(v2): return False -## if id(d1) == id(d2): return False -## return True + def __eq__(self, spc): + """space equality defined as : + * identity, or + * same set of vars with a domain, and + * same name set, and + * equal domains, and + * same set of constraints, and + * different propagators of the same type""" + if not isinstance(spc, ComputationSpace): return False + if id(self) == id(spc): return True + r1 = self.vars == spc.vars + r2 = self.names == spc.names + r3 = self.constraints != spc.constraints + r4 = self.distributor != spc.distributor + r5 = self.root == spc.root + if not r1 and r2 and r3 and r4 and r5: + return False + # now the domains + it1 = [item for item in self.doms.items() + if item[1] != NoDom] + it2 = [item for item in spc.doms.items() + if item[1] != NoDom] + it1.sort() + it2.sort() + for (v1, d1), (v2, d2) in zip (it1, it2): + if v1 != v2: return False + if d1 != d2: return False + if id(v1) != id(v2): return False + if id(d1) == id(d2): return False + return True def __ne__(self, other): return not self == other def pretty_doms(self): print "(-- domains --" - for v, d in self.doms.items(): + doms = self.doms.items() + doms.sort() + for v, d in doms: if d != NoDom: - print ' ', str(d) + print ' ', str(d.get_values()) print " -- domains --)" - def backup_domains(self): - print "-- backup of domains (%s) --" % self.id - doms = [] - for v, d in self.doms.items(): - if d != NoDom: - doms.append((v, len(d))) - doms.sort() - print " (", [elt[1] for elt in doms], ")" - self.domain_history.append(doms) - - def print_quick_diff(self): - ldh = len(self.domain_history) - if ldh > 0: - print "history size (%s) : %s" % (self.id, ldh) - last = self.domain_history[-1] - else: - curr = [(item[0], len(item[1].get_values())) - for item in self.doms.items() - if item[1] != NoDom] - curr.sort() - print "(diff -- v : d 0 (%s)" % self.id - for l in curr: - print ' '*6, '%s : %2d' % (l[0], l[1]) - print " --)" - return - curr = [(item[0], len(item[1].get_values())) - for item in self.doms.items() - if item[1] != NoDom] - curr.sort() - print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, self.id) - for l1, l2 in zip(last, curr): - print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1]) - print " --)" - + #-- Computation Space ----------------------------------------- + #-- space helpers ----------------------------------------- + def _make_choice_var(self): ComputationSpace._nb_choices += 1 ch_var = self.var('__choice__'+str(self._nb_choices)) @@ -236,43 +209,37 @@ def _process(self): """wraps the propagator""" - #XXX: shouldn't only the distributor call it ? - #XXX: this is all sequential, but in the future - # when propagators live in threads and are - # awaken by events on variables, this might - # completely disappear - try: - self.satisfy_all() - except ConsistencyFailure: - self.status = Failed - else: - if not self._distributable(): - self.status = Succeeded + if len(self.event_set): + try: + self.satisfy_all() + except ConsistencyFailure: + self.status = Failed + else: + if not self._distributable(): + self.status = Succeeded def _distributable(self): - try: - if self.status not in (Failed, Succeeded): - for var in self.root.val: - if self.dom(var).size() > 1 : - return True - return False - finally: pass - # in The Book : "the space has one thread that is - # suspended on a choice point with two or more alternatives. - # A space can have at most one choice point; attempting to - # create another gives an error." + if self.status not in (Failed, Succeeded): + for var in self.root.val: + if self.dom(var).size() > 1 : + return True + return False def top_level(self): return self.parent is None + def _notify(self, event): + self.event_set.add(event) + + #-- space official API ------------------------------------ + def ask(self): - #print "SPACE Ask() checks stability ..." - self.STABLE.get() # that's real stability - #print "SPACE is stable, resuming Ask()" + self.STABLE.get() status = self.status in (Failed, Succeeded) if status: return self.status if self._distributable(): - return Alternatives(self.distributor.nb_subdomains()) + return Alternative(self.distributor.nb_subdomains()) + # should be unreachable print "DOMS", [(var, self.doms[var]) for var in self.vars @@ -280,14 +247,12 @@ raise NotImplementedError def clone(self): - # cloning should happen after the space is stable + # did you ask before ... ? assert self.STABLE.is_bound() spc = ComputationSpace(NoProblem, parent=self) print "-- cloning %s to %s --" % (self.id, spc.id) - spc.domain_history = [] - for domset in self.domain_history: - spc.domain_history.append(domset) - assert spc._distributable() + self._notify(event.Clone) + spc._process() spc.distributor.start() return spc @@ -304,13 +269,11 @@ some_number must satisfy 1= 0: + print "history size (%s) : %s" % (space.id, ldh) + last = domain_history[-1] + else: + curr = [(item[0], len(item[1].get_values())) + for item in space.doms.items() + if item[1] != NoDom] + curr.sort() + print "(diff -- v : d 0 (%s)" % space.id + for l in curr: + print ' '*6, '%s : %2d' % (l[0], l[1]) + print " --)" + return + curr = [(item[0], len(item[1].get_values())) + for item in space.doms.items() + if item[1] != NoDom] + curr.sort() + print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, space.id) + for l1, l2 in zip(last, curr): + print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1]) + print " --)" Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Wed Mar 1 15:39:53 2006 @@ -1,6 +1,7 @@ import math, random from threading import Thread from state import Succeeded, Distributable, Failed, Forsaken +from event import Revise def arrange_domains(cs, variables): """build a data structure from var to dom @@ -143,11 +144,11 @@ #XXX: are the domains properly set up ? #self.cs._process() # propagate first #better let clone() do this call - self.cs.STABLE.bind(True) while self.cs._distributable(): if self.cs.status == Forsaken: print "-- distributor (%s) ready for GC --" % self.cs.id break + self.cs.STABLE.bind(True) choice = self.cs.choose(self.nb_subdomains()) print "-- distribution & propagation (%s) --" % self.cs.id self.distribute(choice-1) @@ -171,7 +172,7 @@ int(math.floor((choice + 1) * nb_elts))) self.cs.dom(variable).remove_values(values[:start]) self.cs.dom(variable).remove_values(values[end:]) - self.cs.add_distributed(variable) + self.cs._notify(Revise(variable)) class DichotomyDistributor(SplitDistributor): Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 1 15:39:53 2006 @@ -495,11 +495,11 @@ def test_ask_alternatives(self): spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) ## def test_clone_and_process(self): ## spc = newspace(problems.satisfiable_problem) -## assert spc.ask() == space.Alternatives(2) +## assert spc.ask() == space.Alternative(2) ## new_spc = spc.clone() ## #assert spc == new_spc ## assert new_spc.parent == spc @@ -509,7 +509,7 @@ ## new_spc.add_constraint([z, y], 'z == y') ## new_spc.add_constraint([y], 'y < 2') ## new_spc._process() -## assert spc.ask() == space.Alternatives(2) +## assert spc.ask() == space.Alternative(2) ## assert new_spc.ask() == space.Succeeded def test_clone(self): @@ -524,23 +524,23 @@ def eager_and(t1, t2): return t1 and t2 - while not (eager_and(s1.ask() == space.Succeeded, - s2.ask() == space.Succeeded)): - print "S1 diff : " - s1.print_quick_diff() - print "S2 diff : " - s2.print_quick_diff() + passes = 0 + + while not (eager_and(s2.ask() == space.Succeeded, + s1.ask() == space.Succeeded)): + print "pass n?", passes + print "S1", s1.pretty_doms() + print "S2", s2.pretty_doms() + passes += 1 #assert s1 == s2 - #assert s2 == s1 - assert len(s1.domain_history) == len(s2.domain_history) temp = s2.clone() - assert temp.parent == s2 + temp.ask() + assert temp.parent is s2 assert temp in s2.children s2 = temp s1.commit(1) s2.commit(1) - print "FOoooo..." def test_quickdiff(self): s = newspace(problems.conference_scheduling) @@ -556,10 +556,10 @@ space.add_constraint([y], 'y < 2') spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) new_spc = spc.clone() new_spc.inject(more_constraints) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) assert new_spc.ask() == space.Succeeded def test_merge(self): From auc at codespeak.net Wed Mar 1 15:53:29 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 15:53:29 +0100 (CET) Subject: [pypy-svn] r23832 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301145329.252911007C@code0.codespeak.net> Author: auc Date: Wed Mar 1 15:53:27 2006 New Revision: 23832 Modified: pypy/dist/pypy/lib/logic/computation_space/event.py Log: oops ... Modified: pypy/dist/pypy/lib/logic/computation_space/event.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/event.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/event.py Wed Mar 1 15:53:27 2006 @@ -8,7 +8,7 @@ self.var = var def __eq__(self, other): - if not isinstance(other, Distributed): return False + if not isinstance(other, Revise): return False return self.var == other.var From auc at codespeak.net Wed Mar 1 16:06:04 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 16:06:04 +0100 (CET) Subject: [pypy-svn] r23833 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301150604.458E31007D@code0.codespeak.net> Author: auc Date: Wed Mar 1 16:06:01 2006 New Revision: 23833 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/event.py Log: updated notification mecanism Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 1 16:06:01 2006 @@ -104,7 +104,6 @@ self.root = self.var('__root__') # set up the problem self.bind(self.root, problem(self)) - self._notify(event.NewSpace) self._init_choose_commit() self.distributor.start() else: @@ -118,7 +117,6 @@ self.copy_constraints(parent) # ... self.status = Unknown - self._notify(event.Clone) self.distributor = parent.distributor.__class__(self) self._init_choose_commit() @@ -259,7 +257,6 @@ def inject(self, restricting_problem): """add additional entities into a space""" restricting_problem(self) - self.changelog = [var for var in self.vars] self._process() def commit(self, choice): @@ -397,6 +394,7 @@ def _add_const(self, constraint): self.constraints.add(constraint) + self._notify(event.Inject(constraint)) for var in constraint.affected_variables(): self.var_const_map.setdefault(var, set()) self.var_const_map[var].add(constraint) @@ -495,14 +493,12 @@ def _init_constraint_queue(self): cqueue = [] init_const_set = set() - if event.Clone in self.event_set: - init_const_set = self.constraints - elif event.NewSpace in self.event_set: - init_const_set = self.constraints - else: - for ev in self.event_set: - if isinstance(event, event.Revise): - init_const_set.add(self.var_const_map[ev.var]) + for ev in self.event_set: + if isinstance(ev, event.Revise): + for const in self.var_const_map[ev.var]: + init_const_set.add(const) + elif isinstance(ev, event.Inject): + init_const_set.add(ev.constraint) cqueue = [(const.estimate_cost(), const) for const in init_const_set] Modified: pypy/dist/pypy/lib/logic/computation_space/event.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/event.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/event.py Wed Mar 1 16:06:01 2006 @@ -1,7 +1,10 @@ -class NewSpace: pass - class Clone: pass +class Inject(object): + + def __init__(self, constraint): + self.constraint = constraint + class Revise(object): def __init__(self, var): From auc at codespeak.net Wed Mar 1 16:08:20 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 16:08:20 +0100 (CET) Subject: [pypy-svn] r23834 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301150820.AF6921007D@code0.codespeak.net> Author: auc Date: Wed Mar 1 16:08:18 2006 New Revision: 23834 Modified: pypy/dist/pypy/lib/logic/computation_space/strategies.py Log: fix alternative Modified: pypy/dist/pypy/lib/logic/computation_space/strategies.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/strategies.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/strategies.py Wed Mar 1 16:08:18 2006 @@ -15,7 +15,7 @@ return None elif status == csp.Succeeded: return space - elif status == csp.Alternatives(2): + elif status == csp.Alternative(2): new_space = space.clone() space.commit(1) outcome = do_dfs(space) @@ -50,7 +50,7 @@ if status == csp.Succeeded: print ' '*len(sp_stack), "solution !" solutions.append(space) - elif status == csp.Alternatives(2): + elif status == csp.Alternative(2): print ' '*len(sp_stack), "branches ..." sp1 = space.clone() sp1.commit(1) From auc at codespeak.net Wed Mar 1 16:45:37 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 16:45:37 +0100 (CET) Subject: [pypy-svn] r23836 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301154537.55C361007F@code0.codespeak.net> Author: auc Date: Wed Mar 1 16:45:34 2006 New Revision: 23836 Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: doctored two more tests ;) Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 1 16:45:34 2006 @@ -524,13 +524,10 @@ def eager_and(t1, t2): return t1 and t2 - passes = 0 - while not (eager_and(s2.ask() == space.Succeeded, s1.ask() == space.Succeeded)): - print "pass n?", passes - print "S1", s1.pretty_doms() - print "S2", s2.pretty_doms() + #print "S1", s1.pretty_doms() + #print "S2", s2.pretty_doms() passes += 1 #assert s1 == s2 temp = s2.clone() @@ -541,13 +538,6 @@ s1.commit(1) s2.commit(1) - - def test_quickdiff(self): - s = newspace(problems.conference_scheduling) - while not s.ask() == space.Succeeded: - s.print_quick_diff() - s.commit(1) - def test_inject(self): def more_constraints(space): x, y, z = new_spc.find_vars('x', 'y', 'z') @@ -558,44 +548,32 @@ spc = newspace(problems.satisfiable_problem) assert spc.ask() == space.Alternative(2) new_spc = spc.clone() + new_spc.ask() new_spc.inject(more_constraints) assert spc.ask() == space.Alternative(2) assert new_spc.ask() == space.Succeeded def test_merge(self): - spc = newspace(problems.satisfiable_problem) - x, y, z = spc.find_vars('x', 'y', 'z') - print spc.doms - assert spc.top_level() - assert spc.dom(x) == c.FiniteDomain([-4, -2, -1, 0, - 1, 2, 4]) - assert spc.dom(y) == c.FiniteDomain([0, 2, 3, - 4, 5, 16]) - assert spc.dom(z) == c.FiniteDomain([-2, -1, 0, - 1, 2]) - def more_constraints(space): - x, y, z = space.find_vars('x', 'y', 'z') - space.add_constraint([x], '3 > x > 1') - space.add_constraint([z, y], 'z == -1') - space.add_constraint([y], 'y == 3') - - spc.ask() - nspc = spc.clone() - nspc.inject(more_constraints) - x, y, z = nspc.find_vars('x', 'y', 'z') - assert not nspc.top_level() - for v in nspc.vars: print v, "==", v.val, nspc.dom(v) - assert nspc.dom(x) == c.FiniteDomain([2]) - assert nspc.dom(y) == c.FiniteDomain([3]) - assert nspc.dom(z) == c.FiniteDomain([-1]) - assert nspc.ask() == space.Succeeded - nspc.merge() - assert x.val == 2 - assert y.val == 3 - assert z.val == -1 - assert (x, y, z) == nspc.root.val + x, y, z = new_spc.find_vars('x', 'y', 'z') + space.add_constraint([x], 'x == 0') + space.add_constraint([z, y], 'z == y') + space.add_constraint([y], 'y < 2') + spc = newspace(problems.satisfiable_problem) + assert spc.ask() == space.Alternative(2) + new_spc = spc.clone() + new_spc.ask() + new_spc.inject(more_constraints) + assert spc.ask() == space.Alternative(2) + assert new_spc.ask() == space.Succeeded + x, y, z = new_spc.find_vars('x', 'y', 'z') + res = new_spc.merge() + assert res == (x, y, z) == new_spc.root.val + assert res[0].val == 0 + assert res[1].val == 0 + assert res[2].val == 0 + def test_scheduling_problem_dfs_one_solution(self): sol = strategies.dfs_one(problems.conference_scheduling) From auc at codespeak.net Wed Mar 1 16:46:08 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 16:46:08 +0100 (CET) Subject: [pypy-svn] r23837 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301154608.665F91007D@code0.codespeak.net> Author: auc Date: Wed Mar 1 16:46:05 2006 New Revision: 23837 Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py pypy/dist/pypy/lib/logic/computation_space/problems.py pypy/dist/pypy/lib/logic/computation_space/strategies.py Log: forgot this Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Wed Mar 1 16:46:05 2006 @@ -158,6 +158,7 @@ self.cs._del_var(old_choose_var) self.cs.STABLE.bind(True) # unlocks Ask print "-- distributor terminated (%s) --" % self.cs.id + self.cs.STABLE.bind(True) # it can't hurt ... def distribute(self, choice): Modified: pypy/dist/pypy/lib/logic/computation_space/problems.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/problems.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/problems.py Wed Mar 1 16:46:05 2006 @@ -11,8 +11,8 @@ cs = computation_space x, y, z = cs.var('x'), cs.var('y'), cs.var('z') cs.set_dom(x, c.FiniteDomain([-4, -2, -1, 0, 1, 2, 4])) - cs.set_dom(y, c.FiniteDomain([0, 2, 3, 4, 5, 16])) - cs.set_dom(z, c.FiniteDomain([-2, -1, 0, 1, 2])) + cs.set_dom(y, c.FiniteDomain([0, 1, 2, 4, 8, 16])) + cs.set_dom(z, c.FiniteDomain([0, 1, 2])) cs.add_constraint([x, y, z], 'y==x**2-z') # set up a distribution strategy cs.set_distributor(di.DichotomyDistributor(cs)) Modified: pypy/dist/pypy/lib/logic/computation_space/strategies.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/strategies.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/strategies.py Wed Mar 1 16:46:05 2006 @@ -20,6 +20,7 @@ space.commit(1) outcome = do_dfs(space) if outcome is None: + new_space.ask() new_space.commit(2) return do_dfs(new_space) else: @@ -53,9 +54,11 @@ elif status == csp.Alternative(2): print ' '*len(sp_stack), "branches ..." sp1 = space.clone() + sp1.ask() sp1.commit(1) sp_stack.append(sp1) sp2 = space.clone() + sp2.ask() sp2.commit(2) sp_stack.append(sp2) From mwh at codespeak.net Wed Mar 1 17:24:05 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 1 Mar 2006 17:24:05 +0100 (CET) Subject: [pypy-svn] r23839 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060301162405.710751007C@code0.codespeak.net> Author: mwh Date: Wed Mar 1 17:23:53 2006 New Revision: 23839 Modified: pypy/extradoc/sprintinfo/pycon06/planning.txt Log: tuesday's progress and wednesday's planning. Modified: pypy/extradoc/sprintinfo/pycon06/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/planning.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/planning.txt Wed Mar 1 17:23:53 2006 @@ -7,13 +7,17 @@ - Work on an 'rctypes' module aiming at letting us use a ctypes implementation of an extension module from the compiled pypy-c. - PROGRESS: (armin, michael t, joshua, gene) + MONDAY: (armin, michael t, joshua, gene) work on compatibility with various ctypes versions, in particular cleaning up the ways of teaching the annotator about stuff - TODAY: (armin, michael t, gene, ?joshua) - Work on rtyping, cleaning up existing code. + TUESDAY: (armin, michael t, gene) + More cleanups, and eventually adding a feature: + beginnings of rtyping arrays. + + TODAY: (armin, gene) + More of same. - Writing ctypes implementations of modules to be used by the above tool. @@ -22,14 +26,18 @@ - Implementing Python 2.5 features in PyPy - PROGRESS: (arre, stuart, martin) - Tour of PyPy, implemented builtins all() and any() - Then implemented PEP 308, reminding Arre about the - parser mess, but succeeded. - - TODAY: (arre, stuart, anders, ?martin) - More of same; maybe looking at fixing the stable compiler - mess. + MONDAY: (arre, stuart, martin) + Tour of PyPy, implemented builtins all() and any() + Then implemented PEP 308, reminding Arre about the + parser mess, but succeeded. + + TUESDAY: (arre, stuart, anders) + Some untangling of the stable compiler mess. + Implemented 'with' from PEP 343, missing some tests + and the __future__ support. + + TODAY: (arre, sturart, anders) + Continue, maybe PEP 342. - Implementation of constraints solvers and integration of dataflow variables to PyPy. @@ -44,6 +52,11 @@ PROGRESS: (brian, jan) Work on making tests pass or skip on win32, packaging Unfortunately, Brian is unwell. + + TUESDAY: (pat) + Working on template stuff + TODAY: (pat) + More documentation, and checking in. - JIT stuff @@ -55,22 +68,30 @@ Unbroke the backend, some cleaning up, LLVM compatibility work, ctypes investigation. - TODAY: (richard, bob) - Exception policy stuff, more general LLVM stuff - (pat) - possibly some template cleanups + TUESDAY: (richard, bob) + Some exploration of LLVM's JIT (but mainly LLVM's build + system) + + TODAY: (richard) + ? - ootypesystem improvements/smalltalk/lisp backend - PROGRESS: (nik, samuele) + MONDAY: (nik, samuele) Keyword arguments for methods, partial __init__ support. - TODAY: (nik, samuele, michael h) - More! + TUESDAY: (nik, samuele, michael h) + More PBC, __init__ support. Fought with class attributes. + + TODAY: (nik, samuele, mwh) + More fighting. - Generally experiment with PyPy -- for example, play with transparent distribution of objects or coroutines and stackless features at application level. + TUESDAY: (moshez, mwh) + Played with coroutines a bit. Wrote a new test. + - Have fun! From auc at codespeak.net Wed Mar 1 18:17:55 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 18:17:55 +0100 (CET) Subject: [pypy-svn] r23846 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301171755.284171007A@code0.codespeak.net> Author: auc Date: Wed Mar 1 18:17:54 2006 New Revision: 23846 Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py Log: simplevar, to be used internally by spaces Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Wed Mar 1 18:17:54 2006 @@ -9,6 +9,10 @@ def __str__(self): return "%s already in store" % self.name +class AlreadyBound(VariableException): + def __str__(self): + return "%s is already bound" % self.name + class NotAVariable(VariableException): def __str__(self): return "%s is not a variable" % self.name @@ -20,8 +24,51 @@ class NoDom: pass -class Var(object): - """Single-assignment variable""" +class SimpleVar(object): + def __init__(self, name): + self.name = name + self._val = NoValue + # a condition variable for concurrent access + self._value_condition = threading.Condition() + + # value accessors + def _set_val(self, val): + if val != NoValue: + raise AlreadyBound(self.name) + + def _get_val(self): + return self._val + val = property(_get_val, _set_val) + + def __hash__(self): + return self.name.__hash__() + + def __gt__(self, other): + return self.name.__gt__(other.name) + + # public interface + + def is_bound(self): + return self.val != NoValue + + def bind(self, val): + self.val = val + + def get(self): + """Make threads wait on the variable + being bound in the top-level space + """ + try: + self._value_condition.acquire() + while not self._is_bound(): + self._value_condition.wait() + return self.val + finally: + self._value_condition.release() + + +class Var(SimpleVar): + """Dataflow variable linked to a space""" def __init__(self, name, cs): if name in cs.names: @@ -80,33 +127,8 @@ return isinstance(thing, Var) \ and self.name == thing.name - def __hash__(self): - return self.name.__hash__() - - def __gt__(self, other): - return self.name.__gt__(other.name) - def bind(self, val): """top-level space bind""" self._cs.bind(self, val) is_bound = _is_bound - - - #-- Dataflow ops with concurrent semantics ------ - # should be used by threads that want to block on - # unbound variables - - def get(self): - """Make threads wait on the variable - being bound in the top-level space - """ - try: - self._value_condition.acquire() - while not self._is_bound(): - self._value_condition.wait() - return self.val - finally: - self._value_condition.release() - - From auc at codespeak.net Wed Mar 1 18:19:50 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 18:19:50 +0100 (CET) Subject: [pypy-svn] r23848 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301171950.C1A4B1007A@code0.codespeak.net> Author: auc Date: Wed Mar 1 18:19:44 2006 New Revision: 23848 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py Log: twist to merge, until vars are per-space Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 1 18:19:44 2006 @@ -289,11 +289,15 @@ def merge(self): """binds root vars to their singleton domains """ assert self.status == Succeeded - for var in self.root.val: - var.bind(self.dom(var).get_values()[0]) + # this can't work if we don't copy vars too + #for var in self.root.val: + # var.bind(self.dom(var).get_values()[0]) # shut down the distributor self.CHOOSE.bind(0) - return self.root.val + res = [] + for var in self.root.val: + res.append(self.dom(var).get_values()[0]) + return res def set_distributor(self, dist): self.distributor = dist From auc at codespeak.net Wed Mar 1 18:20:34 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 1 Mar 2006 18:20:34 +0100 (CET) Subject: [pypy-svn] r23849 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060301172034.34DD610082@code0.codespeak.net> Author: auc Date: Wed Mar 1 18:20:32 2006 New Revision: 23849 Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: call to arms : some tests, disabled, need to be fixed Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 1 18:20:32 2006 @@ -484,14 +484,17 @@ assert set(['x', 'y', 'z']) == \ set([var.name for var in spc.root.val]) - def test_ask_success(self): - spc = newspace(problems.one_solution_problem) - assert spc.ask() == space.Succeeded - assert spc.ask() == space.Succeeded +# we need to carefully craft some noop problems +# for these tests + +## def test_ask_success(self): +## spc = newspace(problems.one_solution_problem) +## assert spc.ask() == space.Succeeded +## assert spc.ask() == space.Succeeded - def test_ask_failure(self): - spc = newspace(problems.unsatisfiable_problem) - assert spc.ask() == space.Failed +## def test_ask_failure(self): +## spc = newspace(problems.unsatisfiable_problem) +## assert spc.ask() == space.Failed def test_ask_alternatives(self): spc = newspace(problems.satisfiable_problem) @@ -528,7 +531,6 @@ s1.ask() == space.Succeeded)): #print "S1", s1.pretty_doms() #print "S2", s2.pretty_doms() - passes += 1 #assert s1 == s2 temp = s2.clone() temp.ask() @@ -569,22 +571,27 @@ assert new_spc.ask() == space.Succeeded x, y, z = new_spc.find_vars('x', 'y', 'z') res = new_spc.merge() - assert res == (x, y, z) == new_spc.root.val - assert res[0].val == 0 - assert res[1].val == 0 - assert res[2].val == 0 + assert res == [0, 0, 0] - def test_scheduling_problem_dfs_one_solution(self): + def test_scheduling_dfs_one_solution(self): sol = strategies.dfs_one(problems.conference_scheduling) - sol2 = [var.val for var in sol] - print sol2 - assert True # ;-) since the output keeps - # changing under our feets, better wait ... - - -## def test_scheduling_problem_all_solutions(self): -## sols = strategies.solve_all(problems.conference_scheduling) -## assert len(sols) == 64 + print sol + assert sol == [('room A', 'day 1 PM'), + ('room A', 'day 2 AM'), + ('room C', 'day 2 PM'), + ('room C', 'day 2 AM'), + ('room C', 'day 1 AM'), + ('room C', 'day 1 PM'), + ('room B', 'day 2 AM'), + ('room A', 'day 1 AM'), + ('room B', 'day 2 PM'), + ('room B', 'day 1 AM')] + + + def test_scheduling_all_solutions(self): + sols = strategies.solve_all(problems.conference_scheduling) + assert len(sols) == 64 + print sols From goden at codespeak.net Wed Mar 1 18:44:04 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Wed, 1 Mar 2006 18:44:04 +0100 (CET) Subject: [pypy-svn] r23852 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20060301174404.8EF3410081@code0.codespeak.net> Author: goden Date: Wed Mar 1 18:43:56 2006 New Revision: 23852 Modified: pypy/dist/pypy/rpython/rctypes/rarray.py pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: (arigo, goden) - added specialization of ctypes array access Modified: pypy/dist/pypy/rpython/rctypes/rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/rarray.py Wed Mar 1 18:43:56 2006 @@ -3,6 +3,8 @@ from pypy.rpython import extregistry from pypy.rpython.rmodel import Repr from pypy.rpython.lltypesystem import lltype +from pypy.annotation.pairtype import pairtype +from pypy.rpython.rmodel import IntegerRepr ArrayType = type(ARRAY(c_int, 10)) @@ -20,16 +22,36 @@ self.length = type._length_ entry = extregistry.lookup_type(item_ctype) - r_item = entry.get_repr(rtyper, item_ctype) + self.r_item = entry.get_repr(rtyper, item_ctype) self.lowleveltype = lltype.Ptr( lltype.GcStruct( "CtypesGcArray_%s" % type.__name__, - ( "c_data", lltype.Array(r_item.lowleveltype, + ( "c_data", lltype.Array(self.r_item.lowleveltype, hints={"nolength": True}) ) ) ) +class __extend__(pairtype(ArrayRepr, IntegerRepr)): + def rtype_setitem((r_array, r_int), hop): + v_array, v_index, v_item = hop.inputargs(r_array, lltype.Signed, + r_array.r_item) + inputargs = [v_array, hop.inputconst(lltype.Void, "c_data")] + v_c_data = hop.genop('getsubstruct', + inputargs, + lltype.Ptr(r_array.lowleveltype.TO.c_data) ) + hop.genop('setarrayitem', [v_c_data, v_index, v_item]) + + def rtype_getitem((r_array, r_int), hop): + v_array, v_index = hop.inputargs(r_array, lltype.Signed) + + inputargs = [v_array, hop.inputconst(lltype.Void, "c_data")] + v_c_data = hop.genop('getsubstruct', + inputargs, + lltype.Ptr(r_array.lowleveltype.TO.c_data) ) + return hop.genop('getarrayitem', [v_c_data, v_index], + r_array.r_item.lowleveltype) + def arraytype_specialize_call(hop): r_array = hop.r_result return hop.genop("malloc_varsize", [ Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Wed Mar 1 18:43:56 2006 @@ -537,3 +537,13 @@ assert c_data[9] == 0 py.test.raises(IndexError, "c_data[10]") py.test.raises(TypeError, "len(c_data)") + + def test_specialize_array_access(self): + def test_specialize_array_access(): + my_array = c_int_10() + my_array[0] = 1 + + return my_array[0] + + res = interpret(test_specialize_array_access, []) + assert res == 1 From rxe at codespeak.net Wed Mar 1 18:53:05 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 18:53:05 +0100 (CET) Subject: [pypy-svn] r23854 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060301175305.965EC1007C@code0.codespeak.net> Author: rxe Date: Wed Mar 1 18:53:02 2006 New Revision: 23854 Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Add limited args and return values to calling. Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Wed Mar 1 18:53:02 2006 @@ -50,14 +50,105 @@ return NULL; } -static PyObject *ee_call_noargs(PyExecutionEngine *self, PyObject *args) { +static int from_python_to_args(std::vector &llvmargs, + PyObject *value, + const Type *type) { + // XXX Flesh out + GenericValue res; + if (type->getTypeID() == Type::IntTyID) { + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "expected an integer type"); + return -1; + } + res.IntVal = PyInt_AsLong(value); + llvmargs.push_back(res); + return 0; + } + + std::string err = "unsupported type: " + type->getDescription(); + PyErr_SetString(PyExc_TypeError, err.c_str()); + return -1; +} + +static PyObject *to_python_value(const GenericValue &value, + const Type *type) { + + // special case for strings - it is your own fault if not NULL terminated + if (type->getTypeID() == Type::PointerTyID && + type->getContainedType(0)->getTypeID() == Type::SByteTyID) { + return PyString_FromString((const char *) value.PointerVal); + } - char *fnname; + PyObject *res; - if (!PyArg_ParseTuple(args, "s", &fnname)) { + switch (type->getTypeID()) { + + case Type::VoidTyID: + Py_INCREF(Py_None); + res = Py_None; + break; + + case Type::BoolTyID: + res = PyBool_FromLong((long) value.BoolVal); + break; + + case Type::UByteTyID: + res = PyInt_FromLong((long) value.UByteVal); + break; + + case Type::SByteTyID: + res = PyInt_FromLong((long) value.SByteVal); + break; + + case Type::UShortTyID: + res = PyInt_FromLong((long) value.UShortVal); + break; + + case Type::ShortTyID: + res = PyInt_FromLong((long) value.ShortVal); + break; + + case Type::UIntTyID: + res = PyLong_FromUnsignedLong(value.UIntVal); + break; + + case Type::IntTyID: + res = PyInt_FromLong(value.IntVal); + break; + + case Type::ULongTyID: + res = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value.ULongVal); + break; + + case Type::LongTyID: + res = PyLong_FromLongLong((PY_LONG_LONG) value.ULongVal); + break; + + // XXX the rest + default: + std::string err = "unsupported type: " + type->getDescription(); + PyErr_SetString(PyExc_TypeError, err.c_str()); + res = NULL; + } + + return res; +} + +static PyObject *ee_call(PyExecutionEngine *self, PyObject *args) { + + if (PyTuple_Size(args) == 0) { + PyErr_SetString(PyExc_TypeError, "first arg expected as string"); return NULL; } - + + PyObject *pyfnname = PyTuple_GetItem(args, 0); + if (!PyString_Check(pyfnname)) { + PyErr_SetString(PyExc_TypeError, "first arg expected as string"); + return NULL; + } + + char *fnname = PyString_AsString(pyfnname); + try { Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname)); if (fn == NULL) { @@ -65,21 +156,28 @@ return NULL; } - if (!fn->arg_empty()) { - PyErr_SetString(PyExc_Exception, "Resolved function must take no args"); + unsigned argcount = fn->getFunctionType()->getNumParams(); + if ((unsigned) PyTuple_Size(args) != argcount + 1) { + PyErr_SetString(PyExc_TypeError, "args not much count"); return NULL; - } + } + + std::vector llvmargs; + for (unsigned ii=0; iigetFunctionType()->getParamType(ii)) == -1) { + return NULL; + } + } + + GenericValue ret = self->exec->runFunction(fn, llvmargs); + return to_python_value(ret, fn->getFunctionType()->getReturnType()); - std::vector noargs(0); - GenericValue ret = self->exec->runFunction(fn, noargs); - } catch (...) { PyErr_SetString(PyExc_Exception, "Unexpected unknown exception occurred"); return NULL; } - - Py_INCREF(Py_None); - return Py_None; } static PyObject *ee_functions(PyExecutionEngine *self) { @@ -128,7 +226,7 @@ static PyMethodDef ee_methodlist[] = { {"parse", (PyCFunction) ee_parse, METH_VARARGS, NULL}, {"functions", (PyCFunction) ee_functions, METH_NOARGS, NULL}, - {"call_noargs", (PyCFunction) ee_call_noargs, METH_VARARGS, NULL}, + {"call", (PyCFunction) ee_call, METH_VARARGS, NULL}, {NULL, NULL} }; @@ -209,7 +307,6 @@ } void ee_dealloc(PyExecutionEngine *self) { - // next and prev taken care of by append/remove/dealloc in dlist self->ob_type->tp_free((PyObject*) self); } Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Wed Mar 1 18:53:02 2006 @@ -38,9 +38,15 @@ def test_call1(): ee = get_fresh_ee() ee.parse(codepath.join("hello.s").read()) - ee.call_noargs("hello") - ee.call_noargs("gethellostr") + assert ee.call("hello") == 0 + assert ee.call("gethellostr") == "hello world\n" try: - ee.call_noargs("gethellostrx") + ee.call("gethellostrx") except: pass + try: + ee.call("gethellostr", 1) + except: + pass + ee.parse(codepath.join("addnumbers.s").read()) + assert ee.call("add", 10, 32) == 42 From nik at codespeak.net Wed Mar 1 18:56:55 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 18:56:55 +0100 (CET) Subject: [pypy-svn] r23855 - in pypy/branch/rpython-ooclassattrs: . lltypesystem ootypesystem ootypesystem/test test Message-ID: <20060301175655.651311007C@code0.codespeak.net> Author: nik Date: Wed Mar 1 18:56:45 2006 New Revision: 23855 Modified: pypy/branch/rpython-ooclassattrs/lltypesystem/rclass.py pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py pypy/branch/rpython-ooclassattrs/ootypesystem/rpbc.py pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_ooann.py pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oortype.py pypy/branch/rpython-ooclassattrs/rpbc.py pypy/branch/rpython-ooclassattrs/test/test_rpbc.py Log: (pedronis, nik) lots of prodding and pulling to make class attributes work with ootype. all tests pass again now. branch will be merged shortly. Modified: pypy/branch/rpython-ooclassattrs/lltypesystem/rclass.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/lltypesystem/rclass.py (original) +++ pypy/branch/rpython-ooclassattrs/lltypesystem/rclass.py Wed Mar 1 18:56:45 2006 @@ -224,6 +224,8 @@ return llops.genop('cast_pointer', [vcls], resulttype=self.lowleveltype) + fromclasstype = fromtypeptr + def getclsfield(self, vcls, attr, llops): """Read the given attribute of 'vcls'.""" if attr in self.clsfields: Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/rbuiltin.py Wed Mar 1 18:56:45 2006 @@ -10,11 +10,23 @@ return hop.genop('new', vlist, resulttype = hop.r_result.lowleveltype) +def rtype_null(hop): + assert hop.args_s[0].is_constant() + TYPE = hop.args_s[0].const + nullvalue = ootype.null(TYPE) + return hop.inputconst(TYPE, nullvalue) + def rtype_classof(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOInstance) return hop.genop('classof', hop.args_v, resulttype = ootype.Class) +def rtype_subclassof(hop): + assert isinstance(hop.args_s[0], annmodel.SomeOOClass) + assert isinstance(hop.args_s[1], annmodel.SomeOOClass) + return hop.genop('subclassof', hop.args_v, + resulttype = ootype.Bool) + def rtype_runtimenew(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOClass) return hop.genop('runtimenew', hop.args_v, @@ -48,7 +60,9 @@ BUILTIN_TYPER = {} BUILTIN_TYPER[ootype.new] = rtype_new +BUILTIN_TYPER[ootype.null] = rtype_null BUILTIN_TYPER[ootype.classof] = rtype_classof +BUILTIN_TYPER[ootype.subclassof] = rtype_subclassof BUILTIN_TYPER[ootype.runtimenew] = rtype_runtimenew BUILTIN_TYPER[ootype.ooidentityhash] = rtype_ooidentityhash BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/rclass.py Wed Mar 1 18:56:45 2006 @@ -1,7 +1,9 @@ import types from pypy.annotation import model as annmodel from pypy.annotation import description +from pypy.objspace.flow import model as flowmodel from pypy.rpython.rmodel import inputconst, TyperError +from pypy.rpython.rmodel import mangle as pbcmangle from pypy.rpython.rclass import AbstractClassRepr, AbstractInstanceRepr, \ getinstancerepr, getclassrepr, get_type_repr from pypy.rpython.ootypesystem import ootype @@ -54,7 +56,7 @@ for access_set, counter in extra_access_sets.items(): for attr, s_value in access_set.attrs.items(): r = self.rtyper.getrepr(s_value) - mangled_name = mangle('pbc%d' % counter, attr) + mangled_name = pbcmangle('pbc%d' % counter, attr) pbcfields[access_set, attr] = mangled_name, r llfields.append((mangled_name, r.lowleveltype)) @@ -82,8 +84,8 @@ # setup class attributes: for each attribute name at the level # of 'self', look up its value in the subclass rsubcls def assign(mangled_name, value): - if isinstance(value, Constant) and isinstance(value.value, staticmethod): - value = Constant(value.value.__get__(42)) # staticmethod => bare function + if isinstance(value, flowmodel.Constant) and isinstance(value.value, staticmethod): + value = flowmodel.Constant(value.value.__get__(42)) # staticmethod => bare function llvalue = r.convert_desc_or_const(value) setattr(meta_instance, mangled_name, llvalue) @@ -99,7 +101,7 @@ for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): if rsubcls.classdef.classdesc not in access_set.descs: continue # only for the classes in the same pbc access set - if r.lowleveltype is Void: + if r.lowleveltype is ootype.Void: continue attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) if attrvalue is not None: @@ -112,14 +114,22 @@ getruntime = get_meta_instance - #def getruntime(self): - # return getinstancerepr(self.rtyper, self.classdef).lowleveltype._class + def fromclasstype(self, vclass, llops): + return llops.genop('oodowncast', [vclass], + resulttype=self.lowleveltype) + + def getpbcfield(self, vcls, access_set, attr, llops): + if (access_set, attr) not in self.pbcfields: + raise TyperError("internal error: missing PBC field") + mangled_name, r = self.pbcfields[access_set, attr] + v_meta = self.fromclasstype(vcls, llops) + cname = inputconst(ootype.Void, mangled_name) + return llops.genop('oogetfield', [v_meta, cname], resulttype=r) def rtype_issubtype(self, hop): class_repr = get_type_repr(self.rtyper) vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) return hop.gendirectcall(ll_issubtype, vmeta1, vmeta2) - def ll_issubtype(meta1, meta2): class1 = meta1.class_ class2 = meta2.class_ Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/rpbc.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/rpbc.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/rpbc.py Wed Mar 1 18:56:45 2006 @@ -18,9 +18,15 @@ classdef = hop.s_result.classdef if self.lowleveltype is not ootype.Void: # instantiating a class from multiple possible classes - vclass = hop.inputarg(self, arg=0) + v_meta = hop.inputarg(self, arg=0) + c_class_ = hop.inputconst(ootype.Void, "class_") + v_class = hop.genop('oogetfield', [v_meta, c_class_], + resulttype=ootype.Class) resulttype = getinstancerepr(hop.rtyper, classdef).lowleveltype - v_instance = hop.genop('runtimenew', [vclass], resulttype=resulttype) + v_instance = hop.genop('runtimenew', [v_class], resulttype=resulttype) + c_meta = hop.inputconst(ootype.Void, "meta") + hop.genop('oosetfield', [v_instance, c_meta, v_meta], + resulttype=ootype.Void) else: # instantiating a single class v_instance = rtype_new_instance(hop.rtyper, classdef, hop.llops) Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_ooann.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_ooann.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_ooann.py Wed Mar 1 18:56:45 2006 @@ -57,6 +57,21 @@ assert s == annmodel.SomeOOClass(I) +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + a = RPythonAnnotator() + s = a.build_types(oof, []) + #a.translator.view() + + assert s == annmodel.SomeBool() + def test_simple_runtimenew(): I = Instance("test", ROOT, {'a': Signed}) Modified: pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oortype.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oortype.py (original) +++ pypy/branch/rpython-ooclassattrs/ootypesystem/test/test_oortype.py Wed Mar 1 18:56:45 2006 @@ -72,3 +72,28 @@ assert res is False res = interpret(oof, [False], type_system='ootype') assert res is True + +def test_simple_classof(): + I = Instance("test", ROOT, {'a': Signed}) + + def oof(): + i = new(I) + return classof(i) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Class + +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Bool + Modified: pypy/branch/rpython-ooclassattrs/rpbc.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/rpbc.py (original) +++ pypy/branch/rpython-ooclassattrs/rpbc.py Wed Mar 1 18:56:45 2006 @@ -634,7 +634,7 @@ r_clspbc.rtyper.type_system.rclass.CLASSTYPE) if not r_clspbc.get_class_repr().classdef.issubclass(r_cls.classdef): return NotImplemented - return r_cls.fromtypeptr(v, llops) + return r_cls.fromclasstype(v, llops) class __extend__(pairtype(AbstractClassesPBCRepr, AbstractClassesPBCRepr)): def convert_from_to((r_clspbc1, r_clspbc2), v, llops): Modified: pypy/branch/rpython-ooclassattrs/test/test_rpbc.py ============================================================================== --- pypy/branch/rpython-ooclassattrs/test/test_rpbc.py (original) +++ pypy/branch/rpython-ooclassattrs/test/test_rpbc.py Wed Mar 1 18:56:45 2006 @@ -345,24 +345,24 @@ res = interpret(f1, [], type_system=self.ts) assert res == 1 -def test_call_memo_with_class(): - class A: pass - class FooBar(A): pass - def memofn(cls): - return len(cls.__name__) - memofn._annspecialcase_ = "specialize:memo" - - def f1(i): - if i == 1: - cls = A - else: - cls = FooBar - FooBar() # make sure we have ClassDefs - return memofn(cls) - res = interpret(f1, [1]) - assert res == 1 - res = interpret(f1, [2]) - assert res == 6 + def test_call_memo_with_class(self): + class A: pass + class FooBar(A): pass + def memofn(cls): + return len(cls.__name__) + memofn._annspecialcase_ = "specialize:memo" + + def f1(i): + if i == 1: + cls = A + else: + cls = FooBar + FooBar() # make sure we have ClassDefs + return memofn(cls) + res = interpret(f1, [1], type_system=self.ts) + assert res == 1 + res = interpret(f1, [2], type_system=self.ts) + assert res == 6 def test_rpbc_bound_method_static_call(): class R: From nik at codespeak.net Wed Mar 1 19:02:25 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 19:02:25 +0100 (CET) Subject: [pypy-svn] r23856 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/ootypesystem rpython/ootypesystem/test rpython/test Message-ID: <20060301180225.A2FD61007C@code0.codespeak.net> Author: nik Date: Wed Mar 1 19:02:16 2006 New Revision: 23856 Modified: pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/rpbc.py pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py pypy/dist/pypy/rpython/rclass.py pypy/dist/pypy/rpython/rmodel.py pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) merge class attributes branch r23804:r23855 back into trunk. class attributes now work with ootype. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Wed Mar 1 19:02:16 2006 @@ -464,6 +464,11 @@ assert isinstance(i, SomeOOInstance) return SomeOOClass(i.ootype) +def subclassof(class1, class2): + assert isinstance(class1, SomeOOClass) + assert isinstance(class2, SomeOOClass) + return SomeBool() + def runtimenew(c): assert isinstance(c, SomeOOClass) if c.ootype is None: @@ -480,6 +485,7 @@ BUILTIN_ANALYZERS[ootype.null] = null BUILTIN_ANALYZERS[ootype.runtimenew] = runtimenew BUILTIN_ANALYZERS[ootype.classof] = classof +BUILTIN_ANALYZERS[ootype.subclassof] = subclassof BUILTIN_ANALYZERS[ootype.ooidentityhash] = ooidentityhash #________________________________ Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Wed Mar 1 19:02:16 2006 @@ -565,6 +565,8 @@ return SomeOOInstance(T) elif isinstance(T, ootype.StaticMethod): return SomeOOStaticMeth(T) + elif T == ootype.Class: + return SomeOOClass(ootype.ROOT) else: return SomePtr(T) else: Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Wed Mar 1 19:02:16 2006 @@ -64,6 +64,8 @@ def __ne__(self, other): return not (self == other) + _is_compatible = __eq__ + def __hash__(self): # cannot use saferecursive() -- see test_lltype.test_hash(). # NB. the __cached_hash should neither be used nor updated @@ -1100,6 +1102,7 @@ return result def isCompatibleType(TYPE1, TYPE2): + return TYPE1._is_compatible(TYPE2) return TYPE1 == TYPE2 # mark type ADT methods Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Wed Mar 1 19:02:16 2006 @@ -224,6 +224,8 @@ return llops.genop('cast_pointer', [vcls], resulttype=self.lowleveltype) + fromclasstype = fromtypeptr + def getclsfield(self, vcls, attr, llops): """Read the given attribute of 'vcls'.""" if attr in self.clsfields: Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Wed Mar 1 19:02:16 2006 @@ -1,12 +1,23 @@ from pypy.rpython.lltypesystem.lltype import LowLevelType, Signed, Unsigned, Float, Char -from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, Primitive -from pypy.rpython.lltypesystem.lltype import frozendict +from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \ + Primitive, isCompatibleType +from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType class OOType(LowLevelType): - pass + + def _is_compatible(TYPE1, TYPE2): + if TYPE1 == TYPE2: + return True + if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): + return isSubclass(TYPE1, TYPE2) + else: + return False class Class(OOType): - pass + + def _defl(self): + return nullruntimeclass + Class = Class() class Instance(OOType): @@ -170,7 +181,7 @@ def __setattr__(self, name, value): self.__getattr__(name) - if self._TYPE._field_type(name) != typeOf(value): + if not isCompatibleType(typeOf(value), self._TYPE._field_type(name)): raise TypeError("Expected type %r" % self._TYPE._field_type(name)) self.__dict__[name] = value @@ -333,14 +344,6 @@ c = c._superclass return None -def isCompatibleType(TYPE1, TYPE2): - if TYPE1 == TYPE2: - return True - if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): - return isSubclass(TYPE1, TYPE2) - else: - return False - def ooupcast(INSTANCE, instance): assert instanceof(instance, INSTANCE) return instance Modified: pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py Wed Mar 1 19:02:16 2006 @@ -10,11 +10,23 @@ return hop.genop('new', vlist, resulttype = hop.r_result.lowleveltype) +def rtype_null(hop): + assert hop.args_s[0].is_constant() + TYPE = hop.args_s[0].const + nullvalue = ootype.null(TYPE) + return hop.inputconst(TYPE, nullvalue) + def rtype_classof(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOInstance) return hop.genop('classof', hop.args_v, resulttype = ootype.Class) +def rtype_subclassof(hop): + assert isinstance(hop.args_s[0], annmodel.SomeOOClass) + assert isinstance(hop.args_s[1], annmodel.SomeOOClass) + return hop.genop('subclassof', hop.args_v, + resulttype = ootype.Bool) + def rtype_runtimenew(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOClass) return hop.genop('runtimenew', hop.args_v, @@ -40,7 +52,7 @@ v_obj, v_cls = hop.inputargs(instance_repr, class_repr) if isinstance(v_cls, Constant): - c_cls = hop.inputconst(ootype.Void, v_cls.value._INSTANCE) + c_cls = hop.inputconst(ootype.Void, v_cls.value.class_._INSTANCE) return hop.genop('instanceof', [v_obj, c_cls], resulttype=ootype.Bool) else: raise TyperError("XXX missing impl of isinstance(x, variable)") @@ -48,7 +60,9 @@ BUILTIN_TYPER = {} BUILTIN_TYPER[ootype.new] = rtype_new +BUILTIN_TYPER[ootype.null] = rtype_null BUILTIN_TYPER[ootype.classof] = rtype_classof +BUILTIN_TYPER[ootype.subclassof] = rtype_subclassof BUILTIN_TYPER[ootype.runtimenew] = rtype_runtimenew BUILTIN_TYPER[ootype.ooidentityhash] = rtype_ooidentityhash BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Wed Mar 1 19:02:16 2006 @@ -1,31 +1,139 @@ import types from pypy.annotation import model as annmodel from pypy.annotation import description +from pypy.objspace.flow import model as flowmodel from pypy.rpython.rmodel import inputconst, TyperError +from pypy.rpython.rmodel import mangle as pbcmangle from pypy.rpython.rclass import AbstractClassRepr, AbstractInstanceRepr, \ getinstancerepr, getclassrepr, get_type_repr from pypy.rpython.ootypesystem import ootype from pypy.annotation.pairtype import pairtype from pypy.tool.sourcetools import func_with_new_name -CLASSTYPE = ootype.Class +CLASSTYPE = ootype.Instance("Object_meta", ootype.ROOT, + fields={"class_": ootype.Class}) +OBJECT = ootype.Instance("Object", ootype.ROOT, + fields={'meta': CLASSTYPE}) + class ClassRepr(AbstractClassRepr): def __init__(self, rtyper, classdef): AbstractClassRepr.__init__(self, rtyper, classdef) - self.lowleveltype = ootype.Class + if self.classdef is not None: + self.rbase = getclassrepr(self.rtyper, self.classdef.basedef) + base_type = self.rbase.lowleveltype + self.lowleveltype = ootype.Instance( + self.classdef.name + "_meta", base_type) + else: + # we are ROOT + self.lowleveltype = CLASSTYPE def _setup_repr(self): - pass # not actually needed? + clsfields = {} + pbcfields = {} + if self.classdef is not None: + # class attributes + llfields = [] + """ + attrs = self.classdef.attrs.items() + attrs.sort() + for name, attrdef in attrs: + if attrdef.readonly: + s_value = attrdef.s_value + s_unboundmethod = self.prepare_method(s_value) + if s_unboundmethod is not None: + allmethods[name] = True + s_value = s_unboundmethod + r = self.rtyper.getrepr(s_value) + mangled_name = 'cls_' + name + clsfields[name] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + """ + # attributes showing up in getattrs done on the class as a PBC + extra_access_sets = self.rtyper.class_pbc_attributes.get( + self.classdef, {}) + for access_set, counter in extra_access_sets.items(): + for attr, s_value in access_set.attrs.items(): + r = self.rtyper.getrepr(s_value) + mangled_name = pbcmangle('pbc%d' % counter, attr) + pbcfields[access_set, attr] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + + self.rbase.setup() + ootype.addFields(self.lowleveltype, dict(llfields)) + #self.clsfields = clsfields + self.pbcfields = pbcfields + self.meta_instance = None + + def get_meta_instance(self, cast_to_root_meta=True): + if self.meta_instance is None: + self.meta_instance = ootype.new(self.lowleveltype) + self.setup_meta_instance(self.meta_instance, self) + + meta_instance = self.meta_instance + if cast_to_root_meta: + meta_instance = ootype.ooupcast(CLASSTYPE, meta_instance) + return meta_instance - def getruntime(self): - return getinstancerepr(self.rtyper, self.classdef).lowleveltype._class + def setup_meta_instance(self, meta_instance, rsubcls): + if self.classdef is None: + rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) + setattr(meta_instance, 'class_', rinstance.lowleveltype._class) + else: + # setup class attributes: for each attribute name at the level + # of 'self', look up its value in the subclass rsubcls + def assign(mangled_name, value): + if isinstance(value, flowmodel.Constant) and isinstance(value.value, staticmethod): + value = flowmodel.Constant(value.value.__get__(42)) # staticmethod => bare function + llvalue = r.convert_desc_or_const(value) + setattr(meta_instance, mangled_name, llvalue) + + #mro = list(rsubcls.classdef.getmro()) + #for fldname in self.clsfields: + # mangled_name, r = self.clsfields[fldname] + # if r.lowleveltype is Void: + # continue + # value = rsubcls.classdef.classdesc.read_attribute(fldname, None) + # if value is not None: + # assign(mangled_name, value) + # extra PBC attributes + for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): + if rsubcls.classdef.classdesc not in access_set.descs: + continue # only for the classes in the same pbc access set + if r.lowleveltype is ootype.Void: + continue + attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) + if attrvalue is not None: + assign(mangled_name, attrvalue) + + # then initialize the 'super' portion of the vtable + meta_instance_super = ootype.ooupcast( + self.rbase.lowleveltype, meta_instance) + self.rbase.setup_meta_instance(meta_instance_super, rsubcls) + + getruntime = get_meta_instance + + def fromclasstype(self, vclass, llops): + return llops.genop('oodowncast', [vclass], + resulttype=self.lowleveltype) + + def getpbcfield(self, vcls, access_set, attr, llops): + if (access_set, attr) not in self.pbcfields: + raise TyperError("internal error: missing PBC field") + mangled_name, r = self.pbcfields[access_set, attr] + v_meta = self.fromclasstype(vcls, llops) + cname = inputconst(ootype.Void, mangled_name) + return llops.genop('oogetfield', [v_meta, cname], resulttype=r) def rtype_issubtype(self, hop): class_repr = get_type_repr(self.rtyper) - vlist = hop.inputargs(class_repr, class_repr) - return hop.genop('subclassof', vlist, resulttype=ootype.Bool) + vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) + return hop.gendirectcall(ll_issubtype, vmeta1, vmeta2) +def ll_issubtype(meta1, meta2): + class1 = meta1.class_ + class2 = meta2.class_ + return ootype.subclassof(class1, class2) # ____________________________________________________________ @@ -45,14 +153,14 @@ self.baserepr = None if self.classdef is None: - self.lowleveltype = ootype.ROOT + self.lowleveltype = OBJECT else: b = self.classdef.basedef if b is not None: self.baserepr = getinstancerepr(rtyper, b) b = self.baserepr.lowleveltype else: - b = ootype.ROOT + b = OBJECT self.lowleveltype = ootype.Instance(classdef.shortname, b, {}, {}) self.prebuiltinstances = {} # { id(x): (x, _ptr) } @@ -259,7 +367,8 @@ if hop.args_s[0].can_be_none(): return hop.gendirectcall(ll_inst_type, vinst) else: - return hop.genop('classof', [vinst], resulttype=ootype.Class) + cmeta = inputconst(ootype.Void, "meta") + return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE) def rtype_hash(self, hop): if self.classdef is None: @@ -305,15 +414,23 @@ def new_instance(self, llops): """Build a new instance, without calling __init__.""" - - return llops.genop("new", + classrepr = getclassrepr(self.rtyper, self.classdef) + v_instance = llops.genop("new", [inputconst(ootype.Void, self.lowleveltype)], self.lowleveltype) - + cmeta = inputconst(ootype.Void, "meta") + cmeta_instance = inputconst(CLASSTYPE, classrepr.get_meta_instance()) + llops.genop("oosetfield", [v_instance, cmeta, cmeta_instance], + resulttype=ootype.Void) + return v_instance + def initialize_prebuilt_instance(self, value, result): # then add instance attributes from this level + classrepr = getclassrepr(self.rtyper, self.classdef) for mangled, (oot, default) in self.lowleveltype._allfields().items(): if oot is ootype.Void: llattrvalue = None + elif mangled == 'meta': + llattrvalue = classrepr.get_meta_instance() elif mangled == '_hash_cache_': # hash() support llattrvalue = hash(value) else: @@ -370,7 +487,7 @@ def ll_inst_type(obj): if obj: - return ootype.classof(obj) + return obj.meta else: # type(None) -> NULL (for now) - return ootype.nullruntimeclass + return ootype.null(CLASSTYPE) Modified: pypy/dist/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rpbc.py Wed Mar 1 19:02:16 2006 @@ -18,9 +18,15 @@ classdef = hop.s_result.classdef if self.lowleveltype is not ootype.Void: # instantiating a class from multiple possible classes - vclass = hop.inputarg(self, arg=0) + v_meta = hop.inputarg(self, arg=0) + c_class_ = hop.inputconst(ootype.Void, "class_") + v_class = hop.genop('oogetfield', [v_meta, c_class_], + resulttype=ootype.Class) resulttype = getinstancerepr(hop.rtyper, classdef).lowleveltype - v_instance = hop.genop('runtimenew', [vclass], resulttype=resulttype) + v_instance = hop.genop('runtimenew', [v_class], resulttype=resulttype) + c_meta = hop.inputconst(ootype.Void, "meta") + hop.genop('oosetfield', [v_instance, c_meta, v_meta], + resulttype=ootype.Void) else: # instantiating a single class v_instance = rtype_new_instance(hop.rtyper, classdef, hop.llops) Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py Wed Mar 1 19:02:16 2006 @@ -57,6 +57,21 @@ assert s == annmodel.SomeOOClass(I) +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + a = RPythonAnnotator() + s = a.build_types(oof, []) + #a.translator.view() + + assert s == annmodel.SomeBool() + def test_simple_runtimenew(): I = Instance("test", ROOT, {'a': Signed}) Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py Wed Mar 1 19:02:16 2006 @@ -64,3 +64,20 @@ assert 3 == interpret(f1, [], type_system="ootype") assert 6 == interpret(f2, [], type_system="ootype") +def test_classes_attribute(): + class A: + a = 3 + class B(A): + a = 2 + def f(i): + if i == 1: + cls = B + else: + cls = A + instance = cls() + return cls.a + res = interpret(f, [0], type_system='ootype') + assert res == 3 + res = interpret(f, [1], type_system='ootype') + assert res == 2 + Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py Wed Mar 1 19:02:16 2006 @@ -72,3 +72,28 @@ assert res is False res = interpret(oof, [False], type_system='ootype') assert res is True + +def test_simple_classof(): + I = Instance("test", ROOT, {'a': Signed}) + + def oof(): + i = new(I) + return classof(i) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Class + +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Bool + Modified: pypy/dist/pypy/rpython/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/rclass.py (original) +++ pypy/dist/pypy/rpython/rclass.py Wed Mar 1 19:02:16 2006 @@ -71,7 +71,7 @@ if self.classdef.commonbase(subclassdef) != self.classdef: raise TyperError("not a subclass of %r: %r" % ( self.classdef.name, desc)) - # + return getclassrepr(self.rtyper, subclassdef).getruntime() def convert_const(self, value): Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Wed Mar 1 19:02:16 2006 @@ -4,7 +4,7 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem.lltype import \ Void, Bool, Float, Signed, Char, UniChar, \ - typeOf, LowLevelType, Ptr, PyObject + typeOf, LowLevelType, Ptr, PyObject, isCompatibleType from pypy.rpython.ootypesystem import ootype from pypy.rpython.error import TyperError, MissingRTypeOperation @@ -329,7 +329,7 @@ realtype = typeOf(value) except (AssertionError, AttributeError): realtype = '???' - if realtype != lltype: + if not isCompatibleType(realtype, lltype): raise TyperError("inputconst(reqtype = %s, value = %s):\n" "expected a %r,\n" " got a %r" % (reqtype, value, Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Wed Mar 1 19:02:16 2006 @@ -634,7 +634,7 @@ r_clspbc.rtyper.type_system.rclass.CLASSTYPE) if not r_clspbc.get_class_repr().classdef.issubclass(r_cls.classdef): return NotImplemented - return r_cls.fromtypeptr(v, llops) + return r_cls.fromclasstype(v, llops) class __extend__(pairtype(AbstractClassesPBCRepr, AbstractClassesPBCRepr)): def convert_from_to((r_clspbc1, r_clspbc2), v, llops): Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Wed Mar 1 19:02:16 2006 @@ -345,24 +345,24 @@ res = interpret(f1, [], type_system=self.ts) assert res == 1 -def test_call_memo_with_class(): - class A: pass - class FooBar(A): pass - def memofn(cls): - return len(cls.__name__) - memofn._annspecialcase_ = "specialize:memo" - - def f1(i): - if i == 1: - cls = A - else: - cls = FooBar - FooBar() # make sure we have ClassDefs - return memofn(cls) - res = interpret(f1, [1]) - assert res == 1 - res = interpret(f1, [2]) - assert res == 6 + def test_call_memo_with_class(self): + class A: pass + class FooBar(A): pass + def memofn(cls): + return len(cls.__name__) + memofn._annspecialcase_ = "specialize:memo" + + def f1(i): + if i == 1: + cls = A + else: + cls = FooBar + FooBar() # make sure we have ClassDefs + return memofn(cls) + res = interpret(f1, [1], type_system=self.ts) + assert res == 1 + res = interpret(f1, [2], type_system=self.ts) + assert res == 6 def test_rpbc_bound_method_static_call(): class R: From nik at codespeak.net Wed Mar 1 19:03:36 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 19:03:36 +0100 (CET) Subject: [pypy-svn] r23857 - pypy/branch/rpython-ooclassattrs Message-ID: <20060301180336.3D97610080@code0.codespeak.net> Author: nik Date: Wed Mar 1 19:03:34 2006 New Revision: 23857 Removed: pypy/branch/rpython-ooclassattrs/ Log: delete no longer needed branch From stuart at codespeak.net Wed Mar 1 19:06:01 2006 From: stuart at codespeak.net (stuart at codespeak.net) Date: Wed, 1 Mar 2006 19:06:01 +0100 (CET) Subject: [pypy-svn] r23858 - in pypy/dist/pypy: interpreter interpreter/astcompiler interpreter/test tool Message-ID: <20060301180601.ADDB11006E@code0.codespeak.net> Author: stuart Date: Wed Mar 1 19:06:01 2006 New Revision: 23858 Modified: pypy/dist/pypy/interpreter/astcompiler/pyassem.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/test/test_syntax.py pypy/dist/pypy/tool/opcode.py Log: (Arre, Ale, Stuart Williams) Centralized hack for importing the right opcode module from lib-python/modified-2.4.1. Added more 'with' tests and worked on 'with' code. Modified: pypy/dist/pypy/interpreter/astcompiler/pyassem.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pyassem.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pyassem.py Wed Mar 1 19:06:01 2006 @@ -7,16 +7,7 @@ import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS from pypy.interpreter.pycode import PyCode from pypy.interpreter.baseobjspace import W_Root - -# load opcode.py as pythonopcode from our own lib -def load_opcode(): - import new, py - global pythonopcode - pythonopcode = new.module('opcode') - opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') - execfile(str(opcode_path), pythonopcode.__dict__) - -load_opcode() +from pypy.tool import opcode as pythonopcode class BlockSet: """A Set implementation specific to Blocks Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Mar 1 19:06:01 2006 @@ -14,17 +14,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.rpython.objectmodel import we_are_translated from pypy.rpython.rarithmetic import intmask - -# load opcode.py as pythonopcode from our own lib -def load_opcode(): - import new, py - global pythonopcode - pythonopcode = new.module('opcode') - opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') - execfile(str(opcode_path), pythonopcode.__dict__) - -load_opcode() - +from pypy.tool import opcode as pythonopcode def unaryoperation(operationname): """NOT_RPYTHON""" @@ -648,23 +638,15 @@ f.blockstack.push(block) def WITH_CLEANUP(f): - x = f.valuestack.top() - u = f.valuestack.top(1) - if (f.space.is_w(f.space.type(u), f.space.w_int) - or f.space.is_w(u, f.space.w_None)): - u = v = w = f.space.w_None - else: - v = f.valuestack.top(2) - w = f.valuestack.top(3) - f.valuestack.pop() - f.valuestack.pop() - f.valuestack.pop() - f.valuestack.pop() + v = f.valuestack.top(3) + if (f.space.is_w(v, f.space.w_None)): # no exception + f.valuestack.push(f.space.w_None) f.valuestack.push(f.space.w_None) - f.valuestack.push(x) - f.valuestack.push(u) - f.valuestack.push(v) - f.valuestack.push(w) + f.valuestack.push(f.space.w_None) + else: + f.valuestack.push(v.flowexc.operr.w_type) + f.valuestack.push(v.flowexc.operr.w_value) + f.valuestack.push(v.flowexc.operr.application_traceback) def call_function(f, oparg, w_star=None, w_starstar=None): n_arguments = oparg & 0xff Modified: pypy/dist/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_syntax.py (original) +++ pypy/dist/pypy/interpreter/test/test_syntax.py Wed Mar 1 19:06:01 2006 @@ -257,23 +257,33 @@ assert x == expected class AppTestWith: - def test_with(self): + def test_with_1(self): s = """if 1: # from __future__ import with_statement - class Context: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + pass + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + pass + def __init__(self): self.calls = list() + self.context = self.Context(self) + def __context__(self): self.calls.append('__context__') - return self - def __enter__(self): - self.calls.append('__enter__') - pass - def __exit__(self, exc_type, exc_value, exc_tb): - self.calls.append('__exit__') - pass - acontext = Context() + return self.context + + acontext = ContextFactory() with acontext: pass """ @@ -281,6 +291,87 @@ assert acontext.calls == '__context__ __enter__ __exit__'.split() + def test_with_2(self): + + s = """if 1: + # from __future__ import with_statement + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + with acontextfact as avar: + avar.append('__body__') + pass + """ + exec s + + assert acontextfact.exit_params == (None, None, None) + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + + def test_with_3(self): + + s = """if 1: + # from __future__ import with_statement + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + try: + with acontextfact as avar: + avar.append('__body__') + raise error + avar.append('__after_raise__') + except RuntimeError: + pass + else: + raise AssertionError('With did not raise RuntimeError') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + assert acontextfact.exit_params[0:2] == (RuntimeError, error) + import types + assert isinstance(acontextfact.exit_params[2], types.TracebackType) + if __name__ == '__main__': # only to check on top of CPython (you need 2.4) from py.test import raises Modified: pypy/dist/pypy/tool/opcode.py ============================================================================== --- pypy/dist/pypy/tool/opcode.py (original) +++ pypy/dist/pypy/tool/opcode.py Wed Mar 1 19:06:01 2006 @@ -1,193 +1,9 @@ -# XXX this is a (hopefully temporary) copy of the 2.3 module of CPython. -# See pydis.py. +# load opcode.py as pythonopcode from our own lib +# This should handle missing local copy +def load_opcode(): + import py + opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') + execfile(str(opcode_path), globals()) -""" -opcode module - potentially shared between dis and other modules which -operate on bytecodes (e.g. peephole optimizers). -""" - -__all__ = ["cmp_op", "hasconst", "hasname", "hasjrel", "hasjabs", - "haslocal", "hascompare", "hasfree", "opname", "opmap", - "HAVE_ARGUMENT", "EXTENDED_ARG"] - -cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is', - 'is not', 'exception match', 'BAD') - -hasconst = [] -hasname = [] -hasjrel = [] -hasjabs = [] -haslocal = [] -hascompare = [] -hasfree = [] - -opmap = {} -opname = [''] * 256 -for op in range(256): opname[op] = '<' + `op` + '>' -del op - -def def_op(name, op): - opname[op] = name - opmap[name] = op - -def name_op(name, op): - def_op(name, op) - hasname.append(op) - -def jrel_op(name, op): - def_op(name, op) - hasjrel.append(op) - -def jabs_op(name, op): - def_op(name, op) - hasjabs.append(op) - -# Instruction opcodes for compiled code - -def_op('STOP_CODE', 0) -def_op('POP_TOP', 1) -def_op('ROT_TWO', 2) -def_op('ROT_THREE', 3) -def_op('DUP_TOP', 4) -def_op('ROT_FOUR', 5) -def_op('IEXEC_THROW', 6) - -def_op('UNARY_POSITIVE', 10) -def_op('UNARY_NEGATIVE', 11) -def_op('UNARY_NOT', 12) -def_op('UNARY_CONVERT', 13) - -def_op('UNARY_INVERT', 15) - -def_op('BINARY_POWER', 19) - -def_op('BINARY_MULTIPLY', 20) -def_op('BINARY_DIVIDE', 21) -def_op('BINARY_MODULO', 22) -def_op('BINARY_ADD', 23) -def_op('BINARY_SUBTRACT', 24) -def_op('BINARY_SUBSCR', 25) -def_op('BINARY_FLOOR_DIVIDE', 26) -def_op('BINARY_TRUE_DIVIDE', 27) -def_op('INPLACE_FLOOR_DIVIDE', 28) -def_op('INPLACE_TRUE_DIVIDE', 29) - -def_op('SLICE+0', 30) -def_op('SLICE+1', 31) -def_op('SLICE+2', 32) -def_op('SLICE+3', 33) - -def_op('STORE_SLICE+0', 40) -def_op('STORE_SLICE+1', 41) -def_op('STORE_SLICE+2', 42) -def_op('STORE_SLICE+3', 43) - -def_op('DELETE_SLICE+0', 50) -def_op('DELETE_SLICE+1', 51) -def_op('DELETE_SLICE+2', 52) -def_op('DELETE_SLICE+3', 53) - -def_op('INPLACE_ADD', 55) -def_op('INPLACE_SUBTRACT', 56) -def_op('INPLACE_MULTIPLY', 57) -def_op('INPLACE_DIVIDE', 58) -def_op('INPLACE_MODULO', 59) -def_op('STORE_SUBSCR', 60) -def_op('DELETE_SUBSCR', 61) - -def_op('BINARY_LSHIFT', 62) -def_op('BINARY_RSHIFT', 63) -def_op('BINARY_AND', 64) -def_op('BINARY_XOR', 65) -def_op('BINARY_OR', 66) -def_op('INPLACE_POWER', 67) -def_op('GET_ITER', 68) - -def_op('PRINT_EXPR', 70) -def_op('PRINT_ITEM', 71) -def_op('PRINT_NEWLINE', 72) -def_op('PRINT_ITEM_TO', 73) -def_op('PRINT_NEWLINE_TO', 74) -def_op('INPLACE_LSHIFT', 75) -def_op('INPLACE_RSHIFT', 76) -def_op('INPLACE_AND', 77) -def_op('INPLACE_XOR', 78) -def_op('INPLACE_OR', 79) -def_op('BREAK_LOOP', 80) -def_op('END_IEXEC', 81) - -def_op('LOAD_LOCALS', 82) -def_op('RETURN_VALUE', 83) -def_op('IMPORT_STAR', 84) -def_op('EXEC_STMT', 85) -def_op('YIELD_VALUE', 86) - -def_op('POP_BLOCK', 87) -def_op('END_FINALLY', 88) -def_op('BUILD_CLASS', 89) - -HAVE_ARGUMENT = 90 # Opcodes from here have an argument: - -name_op('STORE_NAME', 90) # Index in name list -name_op('DELETE_NAME', 91) # "" -def_op('UNPACK_SEQUENCE', 92) # Number of tuple items -jrel_op('FOR_ITER', 93) - -name_op('STORE_ATTR', 95) # Index in name list -name_op('DELETE_ATTR', 96) # "" -name_op('STORE_GLOBAL', 97) # "" -name_op('DELETE_GLOBAL', 98) # "" -def_op('DUP_TOPX', 99) # number of items to duplicate -def_op('LOAD_CONST', 100) # Index in const list -hasconst.append(100) -name_op('LOAD_NAME', 101) # Index in name list -def_op('BUILD_TUPLE', 102) # Number of tuple items -def_op('BUILD_LIST', 103) # Number of list items -def_op('BUILD_MAP', 104) # Always zero for now -name_op('LOAD_ATTR', 105) # Index in name list -def_op('COMPARE_OP', 106) # Comparison operator -hascompare.append(106) -name_op('IMPORT_NAME', 107) # Index in name list -name_op('IMPORT_FROM', 108) # Index in name list - -jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip -jrel_op('JUMP_IF_FALSE', 111) # "" -jrel_op('JUMP_IF_TRUE', 112) # "" -jabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code - -name_op('LOAD_GLOBAL', 116) # Index in name list - -jabs_op('CONTINUE_LOOP', 119) # Target address -jrel_op('SETUP_LOOP', 120) # Distance to target address -jrel_op('SETUP_EXCEPT', 121) # "" -jrel_op('SETUP_FINALLY', 122) # "" -jrel_op('SETUP_IEXEC', 123) # "" - -def_op('LOAD_FAST', 124) # Local variable number -haslocal.append(124) -def_op('STORE_FAST', 125) # Local variable number -haslocal.append(125) -def_op('DELETE_FAST', 126) # Local variable number -haslocal.append(126) - -def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) -def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8) -def_op('MAKE_FUNCTION', 132) # Number of args with default values -def_op('BUILD_SLICE', 133) # Number of items - -def_op('MAKE_CLOSURE', 134) -def_op('LOAD_CLOSURE', 135) -hasfree.append(135) -def_op('LOAD_DEREF', 136) -hasfree.append(136) -def_op('STORE_DEREF', 137) -hasfree.append(137) - -def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8) -def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8) -def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8) - -def_op('EXTENDED_ARG', 143) -EXTENDED_ARG = 143 - -del def_op, name_op, jrel_op, jabs_op +load_opcode() +del load_opcode From nik at codespeak.net Wed Mar 1 19:33:51 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 19:33:51 +0100 (CET) Subject: [pypy-svn] r23861 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20060301183351.A6D071007A@code0.codespeak.net> Author: nik Date: Wed Mar 1 19:33:47 2006 New Revision: 23861 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/rclass.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) made two more rpbc tests pass on ootypesystem. pulled some code from both type systems' InstanceRepr up to the abstract base class. Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Wed Mar 1 19:33:47 2006 @@ -368,32 +368,14 @@ def getflavor(self): return self.classdef.classdesc.read_attribute('_alloc_flavor_', Constant('gc')).value - def convert_const(self, value): - if value is None: - return nullptr(self.object_type) - if isinstance(value, types.MethodType): - value = value.im_self # bound method -> instance - cls = value.__class__ - bk = self.rtyper.annotator.bookkeeper - classdef = bk.getdesc(cls).getuniqueclassdef() - if classdef != self.classdef: - # if the class does not match exactly, check that 'value' is an - # instance of a subclass and delegate to that InstanceRepr - if classdef.commonbase(self.classdef) != self.classdef: - raise TyperError("not an instance of %r: %r" % ( - self.classdef.name, value)) - rinstance = getinstancerepr(self.rtyper, classdef) - result = rinstance.convert_const(value) - return cast_pointer(self.lowleveltype, result) - # common case - try: - return self.prebuiltinstances[id(value)][1] - except KeyError: - self.setup() - result = malloc(self.object_type, flavor=self.getflavor()) # pick flavor - self.prebuiltinstances[id(value)] = value, result - self.initialize_prebuilt_instance(value, classdef, result) - return result + def null_instance(self): + return nullptr(self.object_type) + + def upcast(self, result): + return cast_pointer(self.lowleveltype, result) + + def create_instance(self): + return malloc(self.object_type, flavor=self.getflavor()) # pick flavor def get_ll_eq_function(self): return ll_inst_eq Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Wed Mar 1 19:33:47 2006 @@ -130,6 +130,7 @@ class_repr = get_type_repr(self.rtyper) vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) return hop.gendirectcall(ll_issubtype, vmeta1, vmeta2) + def ll_issubtype(meta1, meta2): class1 = meta1.class_ class2 = meta2.class_ @@ -383,34 +384,14 @@ vinst, = hop.inputargs(self) return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed) - def convert_const(self, value): - if value is None: - return ootype.null(self.lowleveltype) - bk = self.rtyper.annotator.bookkeeper - try: - classdef = bk.getuniqueclassdef(value.__class__) - except KeyError: - raise TyperError("no classdef: %r" % (value.__class__,)) - if classdef != self.classdef: - # if the class does not match exactly, check that 'value' is an - # instance of a subclass and delegate to that InstanceRepr - if classdef is None: - raise TyperError("not implemented: object() instance") - if classdef.commonbase(self.classdef) != self.classdef: - raise TyperError("not an instance of %r: %r" % ( - self.classdef.name, value)) - rinstance = getinstancerepr(self.rtyper, classdef) - result = rinstance.convert_const(value) - return ootype.ooupcast(self.lowleveltype, result) - # common case - try: - return self.prebuiltinstances[id(value)][1] - except KeyError: - self.setup() - result = ootype.new(self.object_type) - self.prebuiltinstances[id(value)] = value, result - self.initialize_prebuilt_instance(value, result) - return result + def null_instance(self): + return ootype.null(self.lowleveltype) + + def upcast(self, result): + return ootype.ooupcast(self.lowleveltype, result) + + def create_instance(self): + return ootype.new(self.object_type) def new_instance(self, llops): """Build a new instance, without calling __init__.""" @@ -423,7 +404,7 @@ resulttype=ootype.Void) return v_instance - def initialize_prebuilt_instance(self, value, result): + def initialize_prebuilt_instance(self, value, classdef, result): # then add instance attributes from this level classrepr = getclassrepr(self.rtyper, self.classdef) for mangled, (oot, default) in self.lowleveltype._allfields().items(): Modified: pypy/dist/pypy/rpython/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/rclass.py (original) +++ pypy/dist/pypy/rpython/rclass.py Wed Mar 1 19:33:47 2006 @@ -135,6 +135,35 @@ def new_instance(self, llops): pass + def convert_const(self, value): + if value is None: + return self.null_instance() + if isinstance(value, types.MethodType): + value = value.im_self # bound method -> instance + bk = self.rtyper.annotator.bookkeeper + try: + classdef = bk.getuniqueclassdef(value.__class__) + except KeyError: + raise TyperError("no classdef: %r" % (value.__class__,)) + if classdef != self.classdef: + # if the class does not match exactly, check that 'value' is an + # instance of a subclass and delegate to that InstanceRepr + if classdef.commonbase(self.classdef) != self.classdef: + raise TyperError("not an instance of %r: %r" % ( + self.classdef.name, value)) + rinstance = getinstancerepr(self.rtyper, classdef) + result = rinstance.convert_const(value) + return self.upcast(result) + # common case + try: + return self.prebuiltinstances[id(value)][1] + except KeyError: + self.setup() + result = self.create_instance() + self.prebuiltinstances[id(value)] = value, result + self.initialize_prebuilt_instance(value, classdef, result) + return result + def rtype_type(self, hop): pass Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Wed Mar 1 19:33:47 2006 @@ -364,27 +364,27 @@ res = interpret(f1, [2], type_system=self.ts) assert res == 6 -def test_rpbc_bound_method_static_call(): - class R: - def meth(self): - return 0 - r = R() - m = r.meth - def fn(): - return m() - res = interpret(fn, []) - assert res == 0 - -def test_rpbc_bound_method_static_call_w_kwds(): - class R: - def meth(self, x): - return x - r = R() - m = r.meth - def fn(): - return m(x=3) - res = interpret(fn, []) - assert res == 3 + def test_rpbc_bound_method_static_call(self): + class R: + def meth(self): + return 0 + r = R() + m = r.meth + def fn(): + return m() + res = interpret(fn, [], type_system=self.ts) + assert res == 0 + + def test_rpbc_bound_method_static_call_w_kwds(self): + class R: + def meth(self, x): + return x + r = R() + m = r.meth + def fn(): + return m(x=3) + res = interpret(fn, [], type_system=self.ts) + assert res == 3 def test_constant_return_disagreement(): From arigo at codespeak.net Wed Mar 1 19:58:37 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Mar 2006 19:58:37 +0100 (CET) Subject: [pypy-svn] r23862 - pypy/dist/pypy/doc Message-ID: <20060301185837.87F6810070@code0.codespeak.net> Author: arigo Date: Wed Mar 1 19:58:26 2006 New Revision: 23862 Modified: pypy/dist/pypy/doc/ctypes-integration.txt Log: Reworking the memory layout section of the rctypes document. Modified: pypy/dist/pypy/doc/ctypes-integration.txt ============================================================================== --- pypy/dist/pypy/doc/ctypes-integration.txt (original) +++ pypy/dist/pypy/doc/ctypes-integration.txt Wed Mar 1 19:58:26 2006 @@ -80,46 +80,103 @@ Memory-Layout ------------- +In Ctypes, all instances are mutable boxes containing either some raw +memory with a layout compatible to that of the equivalent C type, or a +reference to such memory. The reference indirection is transparent to +the user; for example, dereferencing a ctypes object "pointer to +structure" results in a "structure" object that doesn't include a copy +of the data, but only a reference to that data. (This is similar to the +C++ notion of reference: it is just a pointer at the machine level, but +at the language level it behaves like the object that it points to, not +like a pointer.) + +We map this to the LLType model as follows. For boxes that embed the +raw memory content:: + + Ptr( GcStruct( "name", + ("c_data", Struct(...) ) ) ) + +where the raw memory content and layout is specified by the +"Struct(...)" part. + +For boxes that don't embed the raw memory content:: + + Ptr( GcStruct( "name", + ("c_data_ref", Ptr(Struct(...)) ) ) ) + +In both cases, the outer GcStruct is needed to make the boxes tracked by +the GC automatically. The "c_data" or "c_data_ref" field either embeds +or references the raw memory; the "Struct(...)" definition specifies the +exact C layout expected for that memory. + +Of course, the "c_data" and "c_data_ref" fields are not visible to the +rpython-level user. This is where an rctype-specific restriction comes +from: it must be possible for the annotator to figure out statically for +each variable if it needs to be implemented with a "c_data" or a +"c_data_ref" field. (The annotation SomeCTypesObject contains a +memorystate field which can be OWNSMEMORY ("c_data" case) or MEMORYALIAS +("c_data_ref" case).) + Primitive Types ~~~~~~~~~~~~~~~ +Ctypes' primitive types are mapped directly to the correspondending PyPy +LLType: Signed, Float, etc. Primitive values can always be copied around, +so there is no needed for the "c_data_ref" case here. We get:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Signed/Float/etc. ) ) ) ) ) + +Note that we don't make "c_data" itself a Signed or Float directly because +in LLType we can't take pointers to Signed or Float, only to Struct or +Array. + +Pointers +~~~~~~~~ +A C pointer behaves like a primitive value, in that it can be copied +around. We get:: -Ctypes' primitive types are mapped directly to the correspondending -PyPy type. + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Ptr(...) ) ) ) ) ) + +However, there is a special case here: the pointer might point to data +owned by another CtypesBox -- i.e. it can point to the "c_data" field of +some other CtypesBox. In this case we must make sure that the other +CtypesBox stays alive. This is done by adding an extra field +referencing the gc box (this field is not otherwise used):: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Ptr(...) ) ) ) + ( "keepalive" + (Ptr(GcStruct("CtypesBox_"))) ) ) ) Structures ~~~~~~~~~~ -Structures will have the following memory layout if they were allocated by ctypes:: +Structures will have the following memory layout (owning their raw memory) +if they were allocated by ctypes:: - Ptr( GcStruct( "CtypesGcStructure_ + Ptr( GcStruct( "CtypesBox_ ( "c_data" - (Struct "C-Data_ + (Struct "C_Data_ *) ) ) ) -We will try hard not to expose the "c-data" member of the structure -at rpython level. - -Structures that result form dereferencing a pointer will have the following -layout:: - - Ptr( GcStruct( "CtypesStructure_ - ( "c_data" - Ptr( Struct( "C-Data_ - *) ) ) ) ) - -Pointers -~~~~~~~~ -Pointers pointing to structures allocated by ctypes will have the following memory layout:: - - Ptr( GcStruct( "CtypesGCPointer_ - "contents" Ptr( GcStruct( "CtypesGcStructure_" ... ) ) ) ) - - -Pointers pointing returned from external functions have the follwing layout if the -point to a structure:: - - Ptr( GcStruct( "CtypesPointer_" - "contents" Ptr( Struct( "CtypesStructure_" ... ) ) ) ) +For structures obtained by dereferencing a pointer (by reading its +"contents" attribute), the structure box does not own the memory:: -Currently it is not decided whether assiging a pointers `contents` attribute from -a GC-pointer should be allowed. The other case will only become valid if we implement -structures with mixed memory state. + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + *) ) ) ) ) + +One or several Keepalive fields might be necessary in each case. +(To be clarified...) + +Arrays +~~~~~~ +Arrays behave like structures, but use an Array instead of a Struct in +the "c_data" or "c_data_ref" declaration. From arigo at codespeak.net Wed Mar 1 22:18:05 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Mar 2006 22:18:05 +0100 (CET) Subject: [pypy-svn] r23863 - pypy/dist/pypy/doc Message-ID: <20060301211805.9276F1008D@code0.codespeak.net> Author: arigo Date: Wed Mar 1 22:17:51 2006 New Revision: 23863 Modified: pypy/dist/pypy/doc/ctypes-integration.txt Log: CTypes: actually, all objects sometimes need an owning or non-owning version. Modified: pypy/dist/pypy/doc/ctypes-integration.txt ============================================================================== --- pypy/dist/pypy/doc/ctypes-integration.txt (original) +++ pypy/dist/pypy/doc/ctypes-integration.txt Wed Mar 1 22:17:51 2006 @@ -120,8 +120,7 @@ Primitive Types ~~~~~~~~~~~~~~~ Ctypes' primitive types are mapped directly to the correspondending PyPy -LLType: Signed, Float, etc. Primitive values can always be copied around, -so there is no needed for the "c_data_ref" case here. We get:: +LLType: Signed, Float, etc. For the owned-memory case, we get:: Ptr( GcStruct( "CtypesBox_ ( "c_data" @@ -132,16 +131,30 @@ in LLType we can't take pointers to Signed or Float, only to Struct or Array. +The non-owned-memory case is:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + ( "value", Signed/Float/etc. ) ) ) ) ) ) + Pointers ~~~~~~~~ -A C pointer behaves like a primitive value, in that it can be copied -around. We get:: + +:: Ptr( GcStruct( "CtypesBox_ ( "c_data" (Struct "C_Data_ ( "value", Ptr(...) ) ) ) ) ) +or:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + ( "value", Ptr(...) ) ) ) ) ) ) + However, there is a special case here: the pointer might point to data owned by another CtypesBox -- i.e. it can point to the "c_data" field of some other CtypesBox. In this case we must make sure that the other From rxe at codespeak.net Wed Mar 1 22:28:41 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 22:28:41 +0100 (CET) Subject: [pypy-svn] r23864 - pypy/dist/pypy/translator/llvm Message-ID: <20060301212841.E5F891006D@code0.codespeak.net> Author: rxe Date: Wed Mar 1 22:28:39 2006 New Revision: 23864 Modified: pypy/dist/pypy/translator/llvm/codewriter.py Log: (mwh, rxe) I (rxe) keep forgetting why we need this... hence the comment. Modified: pypy/dist/pypy/translator/llvm/codewriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/codewriter.py (original) +++ pypy/dist/pypy/translator/llvm/codewriter.py Wed Mar 1 22:28:39 2006 @@ -135,7 +135,12 @@ "%(fromvar)s to %(targettype)s" % locals()) def getelementptr(self, targetvar, type, typevar, indices, getptr=True): - # XXX comment getptr + # getelementptr gives you back a value for the last thing indexed + + # what is getptr? + # --------------- + # All global variables in LLVM are pointers, and pointers must also be + # dereferenced with the getelementptr instruction (hence the uint 0) if getptr: indices = [(self.word_repr, 0)] + list(indices) res = "%(targetvar)s = getelementptr %(type)s %(typevar)s, " % locals() From rxe at codespeak.net Wed Mar 1 22:29:13 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 22:29:13 +0100 (CET) Subject: [pypy-svn] r23865 - pypy/dist/pypy/translator/llvm Message-ID: <20060301212913.9FCA310082@code0.codespeak.net> Author: rxe Date: Wed Mar 1 22:29:10 2006 New Revision: 23865 Modified: pypy/dist/pypy/translator/llvm/codewriter.py Log: tyop Modified: pypy/dist/pypy/translator/llvm/codewriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/codewriter.py (original) +++ pypy/dist/pypy/translator/llvm/codewriter.py Wed Mar 1 22:29:10 2006 @@ -140,7 +140,7 @@ # what is getptr? # --------------- # All global variables in LLVM are pointers, and pointers must also be - # dereferenced with the getelementptr instruction (hence the uint 0) + # dereferenced with the getelementptr instruction (hence the int 0) if getptr: indices = [(self.word_repr, 0)] + list(indices) res = "%(targetvar)s = getelementptr %(type)s %(typevar)s, " % locals() From stuart at codespeak.net Wed Mar 1 22:37:09 2006 From: stuart at codespeak.net (stuart at codespeak.net) Date: Wed, 1 Mar 2006 22:37:09 +0100 (CET) Subject: [pypy-svn] r23866 - in pypy/dist/pypy/interpreter: . astcompiler test Message-ID: <20060301213709.57C4910090@code0.codespeak.net> Author: stuart Date: Wed Mar 1 22:37:03 2006 New Revision: 23866 Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/test/test_syntax.py Log: (Arre, Ale, Stuart Williams) Completed 'with' tests. Made 'with' code generation comply with the tests. Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Wed Mar 1 22:37:03 2006 @@ -561,22 +561,29 @@ self.emitop('LOAD_ATTR', '__enter__') self.emitop_int('CALL_FUNCTION', 0) finally_block = self.newBlock() + body = self.newBlock() + + self.setups.append((TRY_FINALLY, body)) if node.var is not None: # VAR is present self._implicitNameOp('STORE', var) self.emitop_block('SETUP_FINALLY', finally_block) + self.nextBlock(body) self._implicitNameOp('LOAD', var) self._implicitNameOp('DELETE', var) node.var.accept(self) else: self.emit('POP_TOP') self.emitop_block('SETUP_FINALLY', finally_block) + self.nextBlock(body) node.body.accept(self) self.emit('POP_BLOCK') + self.setups.pop() self.emitop_obj('LOAD_CONST', self.space.w_None) # WITH_CLEANUP checks for normal exit self.nextBlock(finally_block) + self.setups.append((END_FINALLY, finally_block)) # find local variable with is context.__exit__ self._implicitNameOp('LOAD', exit) @@ -586,6 +593,7 @@ self.emitop_int('CALL_FUNCTION', 3) self.emit('POP_TOP') self.emit('END_FINALLY') + self.setups.pop() def visitCompare(self, node): node.expr.accept( self ) Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Mar 1 22:37:03 2006 @@ -638,16 +638,19 @@ f.blockstack.push(block) def WITH_CLEANUP(f): - v = f.valuestack.top(3) - if (f.space.is_w(v, f.space.w_None)): # no exception + # see comment in END_FINALLY for stack state + w_unroller = f.valuestack.top(3) + unroller = f.space.interpclass_w(w_unroller) + if (isinstance(unroller, pyframe.SuspendedUnroller) + and isinstance(unroller.flowexc, pyframe.SApplicationException)): + f.valuestack.push(unroller.flowexc.operr.w_type) + f.valuestack.push(unroller.flowexc.operr.w_value) + f.valuestack.push(unroller.flowexc.operr.application_traceback) + else: f.valuestack.push(f.space.w_None) f.valuestack.push(f.space.w_None) f.valuestack.push(f.space.w_None) - else: - f.valuestack.push(v.flowexc.operr.w_type) - f.valuestack.push(v.flowexc.operr.w_value) - f.valuestack.push(v.flowexc.operr.application_traceback) - + def call_function(f, oparg, w_star=None, w_starstar=None): n_arguments = oparg & 0xff n_keywords = (oparg>>8) & 0xff Modified: pypy/dist/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_syntax.py (original) +++ pypy/dist/pypy/interpreter/test/test_syntax.py Wed Mar 1 22:37:03 2006 @@ -372,6 +372,128 @@ import types assert isinstance(acontextfact.exit_params[2], types.TracebackType) + def test_with_4(self): + + s = """if 1: + # from __future__ import with_statement + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + for x in 1,: + with acontextfact as avar: + avar.append('__body__') + break + avar.append('__after_break__') + else: + raise AssertionError('Break failed with With, reached else clause') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + assert acontextfact.exit_params == (None, None, None) + + def test_with_5(self): + + s = """if 1: + # from __future__ import with_statement + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + for x in 1,: + with acontextfact as avar: + avar.append('__body__') + continue + avar.append('__after_break__') + else: + avar.append('__continue__') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __continue__'.split() + assert acontextfact.exit_params == (None, None, None) + + def test_with_6(self): + + s = """if 1: + # from __future__ import with_statement + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + def g(acontextfact): + with acontextfact as avar: + avar.append('__body__') + return '__return__' + avar.append('__after_return__') + acontextfact.calls.append(g(acontextfact)) + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __return__'.split() + assert acontextfact.exit_params == (None, None, None) + if __name__ == '__main__': # only to check on top of CPython (you need 2.4) from py.test import raises From nik at codespeak.net Wed Mar 1 23:02:17 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 23:02:17 +0100 (CET) Subject: [pypy-svn] r23867 - pypy/dist/pypy/rpython/test Message-ID: <20060301220217.B2D2C1008D@code0.codespeak.net> Author: nik Date: Wed Mar 1 23:02:15 2006 New Revision: 23867 Modified: pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) move more rpbc tests over to ootype. had to generalize some tests somewhat to be independent of the used type system. Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Wed Mar 1 23:02:15 2006 @@ -387,103 +387,115 @@ assert res == 3 -def test_constant_return_disagreement(): - class R: - def meth(self): - return 0 - r = R() - def fn(): - return r.meth() - res = interpret(fn, []) - assert res == 0 - -def test_None_is_false(): - def fn(i): - return bool([None, fn][i]) - res = interpret(fn, [1]) - assert res is True - res = interpret(fn, [0]) - assert res is False - -def test_classpbc_getattr(): - class A: - myvalue = 123 - class B(A): - myvalue = 456 - def f(i): - return [A,B][i].myvalue - res = interpret(f, [0]) - assert res == 123 - res = interpret(f, [1]) - assert res == 456 - -def test_function_or_None(): - def g1(): - return 42 - def f(i): - g = None - if i > 5: - g = g1 - if i > 6: - return g() - else: - return 12 - - res = interpret(f, [0]) - assert res == 12 - res = interpret(f, [6]) - assert res == 12 - res = interpret(f, [7]) - assert res == 42 - -def test_classdef_getattr(): - class A: - myvalue = 123 - class B(A): - myvalue = 456 - def f(i): - B() # for A and B to have classdefs - return [A,B][i].myvalue - res = interpret(f, [0]) - assert res == 123 - res = interpret(f, [1]) - assert res == 456 - -def test_call_classes(): - class A: pass - class B(A): pass - def f(i): - if i == 1: - cls = B - else: - cls = A - return cls() - res = interpret(f, [0]) - assert res.super.typeptr.name[0] == 'A' - res = interpret(f, [1]) - assert res.super.typeptr.name[0] == 'B' + def test_constant_return_disagreement(self): + class R: + def meth(self): + return 0 + r = R() + def fn(): + return r.meth() + res = interpret(fn, [], type_system=self.ts) + assert res == 0 + + def test_None_is_false(self): + def fn(i): + if i == 0: + v = None + else: + v = fn + return bool(v) + res = interpret(fn, [1], type_system=self.ts) + assert res is True + res = interpret(fn, [0], type_system=self.ts) + assert res is False + + def test_classpbc_getattr(self): + class A: + myvalue = 123 + class B(A): + myvalue = 456 + def f(i): + if i == 0: + v = A + else: + v = B + return v.myvalue + res = interpret(f, [0], type_system=self.ts) + assert res == 123 + res = interpret(f, [1], type_system=self.ts) + assert res == 456 + + def test_function_or_None(self): + def g1(): + return 42 + def f(i): + g = None + if i > 5: + g = g1 + if i > 6: + return g() + else: + return 12 -def test_call_classes_with_init2(): - class A: - def __init__(self, z): - self.z = z - class B(A): - def __init__(self, z, x=42): - A.__init__(self, z) - self.extra = x - def f(i, z): - if i == 1: - cls = B - else: - cls = A - return cls(z) - res = interpret(f, [0, 5]) - assert res.super.typeptr.name[0] == 'A' - assert res.inst_z == 5 - res = interpret(f, [1, -7645]) - assert res.super.typeptr.name[0] == 'B' - assert res.inst_z == -7645 - assert res._obj._parentstructure().inst_extra == 42 + res = interpret(f, [0], type_system=self.ts) + assert res == 12 + res = interpret(f, [6], type_system=self.ts) + assert res == 12 + res = interpret(f, [7], type_system=self.ts) + assert res == 42 + + def test_classdef_getattr(self): + class A: + myvalue = 123 + class B(A): + myvalue = 456 + def f(i): + B() # for A and B to have classdefs + if i == 0: + v = A + else: + v = B + return v.myvalue + res = interpret(f, [0], type_system=self.ts) + assert res == 123 + res = interpret(f, [1], type_system=self.ts) + assert res == 456 + + def test_call_classes(self): + class A: pass + class B(A): pass + def f(i): + if i == 1: + cls = B + else: + cls = A + return cls() + res = interpret(f, [0], type_system=self.ts) + assert self.class_name(res) == 'A' + res = interpret(f, [1], type_system=self.ts) + assert self.class_name(res) == 'B' + + def test_call_classes_with_init2(self): + class A: + def __init__(self, z): + self.z = z + class B(A): + def __init__(self, z, x=42): + A.__init__(self, z) + self.extra = x + def f(i, z): + if i == 1: + cls = B + else: + cls = A + return cls(z) + res = interpret(f, [0, 5], type_system=self.ts) + assert self.class_name(res) == 'A' + assert self.read_attr(res, "z") == 5 + res = interpret(f, [1, -7645], type_system=self.ts) + assert self.class_name(res) == 'B' + assert self.read_attr(res, "z") == -7645 + assert self.read_attr(res, "extra") == 42 def test_call_starargs(): def g(x=-100, *arg): @@ -1317,7 +1329,26 @@ ts = "lltype" + def class_name(self, value): + return "".join(value.super.typeptr.name)[:-1] + + def read_attr(self, value, attr_name): + value = value._obj + while value is not None: + attr = getattr(value, "inst_" + attr_name, None) + if attr is None: + value = value._parentstructure() + else: + return attr + raise AttributeError() + class TestOotype(BaseTestRPBC): ts = "ootype" + def class_name(self, value): + return typeOf(value)._name + + def read_attr(self, value, attr): + return getattr(value, "o" + attr) + From goden at codespeak.net Wed Mar 1 23:10:40 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Wed, 1 Mar 2006 23:10:40 +0100 (CET) Subject: [pypy-svn] r23868 - pypy/dist/pypy/rpython/rctypes/test Message-ID: <20060301221040.84D4610097@code0.codespeak.net> Author: goden Date: Wed Mar 1 23:10:37 2006 New Revision: 23868 Added: pypy/dist/pypy/rpython/rctypes/test/__init__.py pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: - (arigo, goden) - changed test_rctypes to look for the fully qualified path in sys.modules when checking if the test extension module was imported correctly. before the module name would appear in sys.modules but with an __init__.py file in the rpython/rctypes/test directory the full name appears. Moved the Ctypes Array annotation & specialization tests to test_rarray.py from test_rctypes.py. Added: pypy/dist/pypy/rpython/rctypes/test/__init__.py ============================================================================== Added: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Wed Mar 1 23:10:37 2006 @@ -0,0 +1,150 @@ +""" +Test the rctypes implementation. +""" + +import py.test +from pypy.annotation.annrpython import RPythonAnnotator +from pypy.translator.translator import TranslationContext +from pypy import conftest +import sys +from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.rctypes.test.test_rctypes import compile + +try: + import ctypes +except ImportError: + py.test.skip("this test needs ctypes installed") + +from pypy.rpython.rctypes import cdll, c_char_p, c_int, c_char, \ + c_char, c_byte, c_ubyte, c_short, c_ushort, c_uint,\ + c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ + POINTER, Structure, byref, ARRAY + +c_int_10 = ARRAY(c_int,10) +c_int_p_test = POINTER(c_int) + +class Test_array: + def test_annotate_array(self): + def create_array(): + return c_int_10() + + a = RPythonAnnotator() + s = a.build_types(create_array, []) + assert s.knowntype == c_int_10 + + if conftest.option.view: + a.translator.view() + + def test_annotate_array_access(self): + def access_array(): + my_array = c_int_10() + my_array[0] = c_int(1) + my_array[1] = 2 + + return my_array[0] + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(access_array, []) + assert s.knowntype == int + + if conftest.option.view: + t.view() + + def test_annotate_pointer_access_as_array(self): + """ + Make sure that pointers work the same way as arrays, for + ctypes compatibility. + + :Note: This works because pointer and array classes both + have a _type_ attribute, that contains the type of the + object pointed to or in the case of an array the element type. + """ + def access_array(): + # Never run this function! + # See test_annotate_pointer_access_as_array_or_whatever + # for the weird reasons why this gets annotated + my_pointer = c_int_p_test(10) + my_pointer[0] = c_int(1) + my_pointer[1] = 2 + + return my_pointer[0] + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(access_array, []) + assert s.knowntype == int + #d#t.view() + + def test_annotate_array_slice_access(self): + def slice_access(): + my_array = c_int_10() + #f#my_array[0:7] = c_int(1) * 7 + my_array[0:5] = range(5) + + return my_array[0:5] + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(slice_access, []) + #d#t.view() + #d#print "v90:", s, type(s) + assert s.knowntype == list + s.listdef.listitem.s_value.knowntype == int + + def test_annotate_array_access_variable(self): + def access_with_variable(): + my_array = c_int_10() + my_array[2] = 2 + sum = 0 + for idx in range(10): + sum += my_array[idx] + + return sum + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(access_with_variable, []) + assert s.knowntype == int + #t#t.view() + + def test_annotate_array_access_index_error_on_positive_index(self): + def access_with_invalid_positive_index(): + my_array = c_int_10() + return my_array[10] + + t = TranslationContext() + a = t.buildannotator() + + py.test.raises(IndexError, "s = a.build_types(access_with_invalid_positive_index,[])") + + def test_annotate_array_access_index_error_on_negative_index(self): + def access_with_invalid_negative_index(): + my_array = c_int_10() + return my_array[-11] + + t = TranslationContext() + a = t.buildannotator() + + py.test.raises(IndexError, "s = a.build_types(access_with_invalid_negative_index,[])") + + def test_specialize_array(self): + def create_array(): + return c_int_10() + + res = interpret(create_array, []) + c_data = res.c_data + assert c_data[0] == 0 + assert c_data[9] == 0 + py.test.raises(IndexError, "c_data[10]") + py.test.raises(TypeError, "len(c_data)") + + def test_specialize_array_access(self): + def access_array(): + my_array = c_int_10() + my_array[0] = 1 + + return my_array[0] + + res = interpret(access_array, []) + assert res == 1 Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Wed Mar 1 23:10:37 2006 @@ -274,10 +274,10 @@ class Test_structure: def test_simple_as_extension_module(self): - import _rctypes_test as t0 - import _rctypes_test as t1 + import pypy.rpython.rctypes.test._rctypes_test as t0 + import pypy.rpython.rctypes.test._rctypes_test as t1 assert t1 is t0 - assert "_rctypes_test" in sys.modules + assert "pypy.rpython.rctypes.test._rctypes_test" in sys.modules def test_simple(self): if sys.platform == "win32": From rxe at codespeak.net Wed Mar 1 23:17:26 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Mar 2006 23:17:26 +0100 (CET) Subject: [pypy-svn] r23869 - in pypy/dist/pypy/translator/llvm: . test Message-ID: <20060301221726.3CC0D10071@code0.codespeak.net> Author: rxe Date: Wed Mar 1 23:17:22 2006 New Revision: 23869 Added: pypy/dist/pypy/translator/llvm/test/test_symbolic.py (contents, props changed) Modified: pypy/dist/pypy/translator/llvm/codewriter.py pypy/dist/pypy/translator/llvm/database.py pypy/dist/pypy/translator/llvm/opwriter.py Log: (mwh, rxe) Added offset reprs in database and added tests for symbolic offsets. Moved getindexhelper to a more amenable place for others to use. Modified: pypy/dist/pypy/translator/llvm/codewriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/codewriter.py (original) +++ pypy/dist/pypy/translator/llvm/codewriter.py Wed Mar 1 23:17:22 2006 @@ -141,6 +141,10 @@ # --------------- # All global variables in LLVM are pointers, and pointers must also be # dereferenced with the getelementptr instruction (hence the int 0) + + # not only that, but if we need to look into something (ie a struct) + # then we must get the initial pointer to ourself + if getptr: indices = [(self.word_repr, 0)] + list(indices) res = "%(targetvar)s = getelementptr %(type)s %(typevar)s, " % locals() Modified: pypy/dist/pypy/translator/llvm/database.py ============================================================================== --- pypy/dist/pypy/translator/llvm/database.py (original) +++ pypy/dist/pypy/translator/llvm/database.py Wed Mar 1 23:17:22 2006 @@ -5,7 +5,7 @@ from pypy.translator.llvm.funcnode import FuncNode, FuncTypeNode from pypy.translator.llvm.extfuncnode import ExternalFuncNode from pypy.translator.llvm.structnode import StructNode, StructVarsizeNode, \ - StructTypeNode, StructVarsizeTypeNode + StructTypeNode, StructVarsizeTypeNode, getindexhelper from pypy.translator.llvm.arraynode import ArrayNode, StrArrayNode, \ VoidArrayNode, ArrayTypeNode, VoidArrayTypeNode from pypy.translator.llvm.opaquenode import OpaqueNode, ExtOpaqueNode, \ @@ -366,10 +366,39 @@ # XXXXX things are happening in the gc world... # assert value == NULL repr = 'null' + elif isinstance(value, llmemory.AddressOffset): + return self.offset_str(value) else: repr = str(value) return repr + def offset_str(self, value): + + #XXX Need to understand and doc this better + + if isinstance(value, llmemory.FieldOffset): + pos = getindexhelper(value.fldname, value.TYPE) + return "cast(%s* getelementptr(%s* null, int 0, uint %s) to int)" % ( + self.repr_type(getattr(value.TYPE, value.fldname)), + self.repr_type(value.TYPE), + pos) + + elif isinstance(value, llmemory.ItemOffset): + return "cast(%s* getelementptr(%s* null, int %s) to int)" % ( + self.repr_type(value.TYPE), self.repr_type(value.TYPE), value.repeat) + + elif isinstance(value, llmemory.ArrayItemsOffset): + return "cast(%s* getelementptr(%s* null, int 0, uint 1) to int)" % ( + self.repr_type(value.TYPE.OF), self.repr_type(value.TYPE)) + + elif isinstance(value, llmemory.CompositeOffset): + return "cast(%s* getelementptr(%s* null, int 0, uint 1, int %s) to int)" % ( + self.repr_type(value.second.TYPE), + self.repr_type(value.first.TYPE), + value.second.repeat) + else: + raise Exception("unsupported offset") + def get_machine_word(self): return self.primitives[lltype.Signed] Modified: pypy/dist/pypy/translator/llvm/opwriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/opwriter.py (original) +++ pypy/dist/pypy/translator/llvm/opwriter.py Wed Mar 1 23:17:22 2006 @@ -1,6 +1,8 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype from pypy.translator.llvm.log import log +from pypy.translator.llvm.structnode import getindexhelper + log = log.opwriter class OpRepr(object): @@ -313,21 +315,11 @@ else: raise NotImplementedError - def _getindexhelper(self, name, struct): - assert name in list(struct._names) - - fieldnames = struct._names_without_voids() - try: - index = fieldnames.index(name) - except ValueError: - index = -1 - return index - def getfield(self, opr): op = opr.op if opr.rettype != "void": - index = self._getindexhelper(op.args[1].value, - op.args[0].concretetype.TO) + index = getindexhelper(op.args[1].value, + op.args[0].concretetype.TO) assert index != -1 tmpvar = self._tmp() self.codewriter.getelementptr(tmpvar, opr.argtypes[0], @@ -337,8 +329,8 @@ self._skipped(opr) def getsubstruct(self, opr): - index = self._getindexhelper(opr.op.args[1].value, - opr.op.args[0].concretetype.TO) + index = getindexhelper(opr.op.args[1].value, + opr.op.args[0].concretetype.TO) assert opr.rettype != "void" self.codewriter.getelementptr(opr.retref, opr.argtypes[0], opr.argrefs[0], [("uint", index)]) @@ -347,8 +339,8 @@ op = opr.op if opr.argtypes[2] != "void": tmpvar = self._tmp() - index = self._getindexhelper(op.args[1].value, - op.args[0].concretetype.TO) + index = getindexhelper(op.args[1].value, + op.args[0].concretetype.TO) self.codewriter.getelementptr(tmpvar, opr.argtypes[0], opr.argrefs[0], [("uint", index)]) self.codewriter.store(opr.argtypes[2], opr.argrefs[2], tmpvar) Added: pypy/dist/pypy/translator/llvm/test/test_symbolic.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/test/test_symbolic.py Wed Mar 1 23:17:22 2006 @@ -0,0 +1,90 @@ +import py +from pypy.translator.interactive import Translation +from pypy import conftest +from pypy.rpython.lltypesystem import llmemory, lltype +from pypy.rpython.memory import lladdress + +from pypy.translator.llvm.test.runtest import compile_function + +def test_offsetof(): + STRUCT = lltype.GcStruct("s", ("x", lltype.Signed), ("y", lltype.Signed)) + offsetx = llmemory.offsetof(STRUCT, 'x') + offsety = llmemory.offsetof(STRUCT, 'y') + def f(): + s = lltype.malloc(STRUCT) + s.x = 1 + adr = llmemory.cast_ptr_to_adr(s) + result = (adr + offsetx).signed[0] + (adr + offsety).signed[0] = 2 + return result * 10 + s.y + fn = compile_function(f, []) + res = fn() + assert res == 12 + +def test_offsetof(): + STRUCT = lltype.GcStruct("s", ("x", lltype.Signed), ("y", lltype.Signed)) + offsetx = llmemory.offsetof(STRUCT, 'x') + offsety = llmemory.offsetof(STRUCT, 'y') + def f(): + s = lltype.malloc(STRUCT) + s.x = 1 + adr = llmemory.cast_ptr_to_adr(s) + result = (adr + offsetx).signed[0] + (adr + offsety).signed[0] = 2 + return result * 10 + s.y + fn = compile_function(f, []) + res = fn() + assert res == 12 + +def test_sizeof_array_with_no_length(): + py.test.skip("inprogress") + A = lltype.GcArray(lltype.Signed, hints={'nolength': True}) + a = lltype.malloc(A, 5) + + arraysize = llmemory.itemoffsetof(A, 10) + signedsize = llmemory.sizeof(lltype.Signed) + def f(): + return a[0] + arraysize-signedsize*10 + fn = compile_function(f, []) + res = fn() + assert res == 0 + +def test_itemoffsetof(): + ARRAY = lltype.GcArray(lltype.Signed) + itemoffsets = [llmemory.itemoffsetof(ARRAY, i) for i in range(5)] + def f(): + a = lltype.malloc(ARRAY, 5) + adr = llmemory.cast_ptr_to_adr(a) + result = 0 + for i in range(5): + a[i] = i + 1 + for i in range(5): + result = result * 10 + (adr + itemoffsets[i]).signed[0] + for i in range(5): + (adr + itemoffsets[i]).signed[0] = i + for i in range(5): + result = 10 * result + a[i] + return result + fn = compile_function(f, []) + res = fn() + assert res == 1234501234 + +def test_sizeof_constsize_struct(): + # _not_ a GcStruct, since we want to raw_malloc it + STRUCT = lltype.Struct("s", ("x", lltype.Signed), ("y", lltype.Signed)) + STRUCTPTR = lltype.Ptr(STRUCT) + sizeofs = llmemory.sizeof(STRUCT) + offsety = llmemory.offsetof(STRUCT, 'y') + def f(): + adr = lladdress.raw_malloc(sizeofs) + s = llmemory.cast_adr_to_ptr(adr, STRUCTPTR) + s.y = 5 # does not crash + result = (adr + offsety).signed[0] * 10 + int(offsety < sizeofs) + lladdress.raw_free(adr) + return result + + fn = compile_function(f, []) + res = fn() + assert res == 51 + + From nik at codespeak.net Wed Mar 1 23:19:15 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 23:19:15 +0100 (CET) Subject: [pypy-svn] r23870 - pypy/dist/pypy/rpython/test Message-ID: <20060301221915.A7D5110071@code0.codespeak.net> Author: nik Date: Wed Mar 1 23:19:08 2006 New Revision: 23870 Modified: pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) move more rpbc tests over to ootypesystem, all passing. but we just hit a failing one that will be tackled next. Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Wed Mar 1 23:19:08 2006 @@ -497,313 +497,313 @@ assert self.read_attr(res, "z") == -7645 assert self.read_attr(res, "extra") == 42 -def test_call_starargs(): - def g(x=-100, *arg): - return x + len(arg) - def f(i): - if i == -1: - return g() - elif i == 0: - return g(4) - elif i == 1: - return g(5, 15) - elif i == 2: - return g(7, 17, 27) - else: - return g(10, 198, 1129, 13984) - res = interpret(f, [-1]) - assert res == -100 - res = interpret(f, [0]) - assert res == 4 - res = interpret(f, [1]) - assert res == 6 - res = interpret(f, [2]) - assert res == 9 - res = interpret(f, [3]) - assert res == 13 - -def test_conv_from_None(): - class A(object): pass - def none(): - return None - - def f(i): - if i == 1: - return none() - else: - return "ab" - res = interpret(f, [1]) - assert not res - res = interpret(f, [0]) - assert ''.join(res.chars) == "ab" + def test_conv_from_None(self): + class A(object): pass + def none(): + return None - def g(i): - if i == 1: - return none() - else: - return A() - res = interpret(g, [1]) - assert not res - res = interpret(g, [0]) - assert res.super.typeptr.name[0] == 'A' + def f(i): + if i == 1: + return none() + else: + return "ab" + res = interpret(f, [1], type_system=self.ts) + assert not res + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == "ab" + + def g(i): + if i == 1: + return none() + else: + return A() + res = interpret(g, [1], type_system=self.ts) + assert not res + res = interpret(g, [0], type_system=self.ts) + assert self.class_name(res) == 'A' -def test_conv_from_classpbcset_to_larger(): - class A(object): pass - class B(A): pass - class C(A): pass - - def a(): - return A - def b(): - return B - - - def g(i): - if i == 1: - cls = a() - else: - cls = b() - return cls() - - res = interpret(g, [0]) - assert res.super.typeptr.name[0] == 'B' - res = interpret(g, [1]) - assert res.super.typeptr.name[0] == 'A' - - def bc(j): - if j == 1: + def test_conv_from_classpbcset_to_larger(self): + class A(object): pass + class B(A): pass + class C(A): pass + + def a(): + return A + def b(): return B - else: - return C - - def g(i, j): - if i == 1: - cls = a() - else: - cls = bc(j) - return cls() + - res = interpret(g, [0, 0]) - assert res.super.typeptr.name[0] == 'C' - res = interpret(g, [0, 1]) - assert res.super.typeptr.name[0] == 'B' - res = interpret(g, [1, 0]) - assert res.super.typeptr.name[0] == 'A' - -def test_call_keywords(): - def g(a=1, b=2, c=3): - return 100*a+10*b+c + def g(i): + if i == 1: + cls = a() + else: + cls = b() + return cls() - def f(i): - if i == 0: - return g(a=7) - elif i == 1: - return g(b=11) - elif i == 2: - return g(c=13) - elif i == 3: - return g(a=7, b=11) - elif i == 4: - return g(b=7, a=11) - elif i == 5: - return g(a=7, c=13) - elif i == 6: - return g(c=7, a=13) - elif i == 7: - return g(a=7,b=11,c=13) - elif i == 8: - return g(a=7,c=11,b=13) - elif i == 9: - return g(b=7,a=11,c=13) - else: - return g(b=7,c=11,a=13) + res = interpret(g, [0], type_system=self.ts) + assert self.class_name(res) == 'B' + res = interpret(g, [1], type_system=self.ts) + assert self.class_name(res) == 'A' + + def bc(j): + if j == 1: + return B + else: + return C - for i in range(11): - res = interpret(f, [i]) - assert res == f(i) + def g(i, j): + if i == 1: + cls = a() + else: + cls = bc(j) + return cls() -def test_call_star_and_keywords(): - def g(a=1, b=2, c=3): - return 100*a+10*b+c - - def f(i, x): - if x == 1: - j = 11 - else: - j = 22 - if i == 0: - return g(7) - elif i == 1: - return g(7,*(j,)) - elif i == 2: - return g(7,*(11,j)) - elif i == 3: - return g(a=7) - elif i == 4: - return g(b=7, *(j,)) - elif i == 5: - return g(b=7, c=13, *(j,)) - elif i == 6: - return g(c=7, b=13, *(j,)) - elif i == 7: - return g(c=7,*(j,)) - elif i == 8: - return g(c=7,*(11,j)) - else: - return 0 - - for i in range(9): - for x in range(1): - res = interpret(f, [i, x]) - assert res == f(i, x) - -def test_call_star_and_keywords_starargs(): - def g(a=1, b=2, c=3, *rest): - return 1000*len(rest)+100*a+10*b+c - - def f(i, x): - if x == 1: - j = 13 - else: - j = 31 - if i == 0: - return g() - elif i == 1: - return g(*(j,)) - elif i == 2: - return g(*(13, j)) - elif i == 3: - return g(*(13, j, 19)) - elif i == 4: - return g(*(13, j, 19, 21)) - elif i == 5: - return g(7) - elif i == 6: - return g(7, *(j,)) - elif i == 7: - return g(7, *(13, j)) - elif i == 8: - return g(7, *(13, 17, j)) - elif i == 9: - return g(7, *(13, 17, j, 21)) - elif i == 10: - return g(7, 9) - elif i == 11: - return g(7, 9, *(j,)) - elif i == 12: - return g(7, 9, *(j, 17)) - elif i == 13: - return g(7, 9, *(13, j, 19)) - elif i == 14: - return g(7, 9, 11) - elif i == 15: - return g(7, 9, 11, *(j,)) - elif i == 16: - return g(7, 9, 11, *(13, j)) - elif i == 17: - return g(7, 9, 11, *(13, 17, j)) - elif i == 18: - return g(7, 9, 11, 2) - elif i == 19: - return g(7, 9, 11, 2, *(j,)) - elif i == 20: - return g(7, 9, 11, 2, *(13, j)) - else: - return 0 - - for i in range(21): - for x in range(1): - res = interpret(f, [i, x]) - assert res == f(i, x) - -def test_conv_from_funcpbcset_to_larger(): - def f1(): - return 7 - def f2(): - return 11 - def f3(): - return 13 - - def a(): - return f1 - def b(): - return f2 - + res = interpret(g, [0, 0], type_system=self.ts) + assert self.class_name(res) == 'C' + res = interpret(g, [0, 1], type_system=self.ts) + assert self.class_name(res) == 'B' + res = interpret(g, [1, 0], type_system=self.ts) + assert self.class_name(res) == 'A' + + def test_call_starargs(self): + def g(x=-100, *arg): + return x + len(arg) + def f(i): + if i == -1: + return g() + elif i == 0: + return g(4) + elif i == 1: + return g(5, 15) + elif i == 2: + return g(7, 17, 27) + else: + return g(10, 198, 1129, 13984) + res = interpret(f, [-1], type_system=self.ts) + assert res == -100 + res = interpret(f, [0], type_system=self.ts) + assert res == 4 + res = interpret(f, [1], type_system=self.ts) + assert res == 6 + res = interpret(f, [2], type_system=self.ts) + assert res == 9 + res = interpret(f, [3], type_system=self.ts) + assert res == 13 + + def test_call_keywords(self): + def g(a=1, b=2, c=3): + return 100*a+10*b+c + + def f(i): + if i == 0: + return g(a=7) + elif i == 1: + return g(b=11) + elif i == 2: + return g(c=13) + elif i == 3: + return g(a=7, b=11) + elif i == 4: + return g(b=7, a=11) + elif i == 5: + return g(a=7, c=13) + elif i == 6: + return g(c=7, a=13) + elif i == 7: + return g(a=7,b=11,c=13) + elif i == 8: + return g(a=7,c=11,b=13) + elif i == 9: + return g(b=7,a=11,c=13) + else: + return g(b=7,c=11,a=13) - def g(i): - if i == 1: - f = a() - else: - f = b() - return f() + for i in range(11): + res = interpret(f, [i], type_system=self.ts) + assert res == f(i) + + def test_call_star_and_keywords(self): + def g(a=1, b=2, c=3): + return 100*a+10*b+c + + def f(i, x): + if x == 1: + j = 11 + else: + j = 22 + if i == 0: + return g(7) + elif i == 1: + return g(7,*(j,)) + elif i == 2: + return g(7,*(11,j)) + elif i == 3: + return g(a=7) + elif i == 4: + return g(b=7, *(j,)) + elif i == 5: + return g(b=7, c=13, *(j,)) + elif i == 6: + return g(c=7, b=13, *(j,)) + elif i == 7: + return g(c=7,*(j,)) + elif i == 8: + return g(c=7,*(11,j)) + else: + return 0 - res = interpret(g, [0]) - assert res == 11 - res = interpret(g, [1]) - assert res == 7 + for i in range(9): + for x in range(1): + res = interpret(f, [i, x], type_system=self.ts) + assert res == f(i, x) + + def test_call_star_and_keywords_starargs(self): + def g(a=1, b=2, c=3, *rest): + return 1000*len(rest)+100*a+10*b+c + + def f(i, x): + if x == 1: + j = 13 + else: + j = 31 + if i == 0: + return g() + elif i == 1: + return g(*(j,)) + elif i == 2: + return g(*(13, j)) + elif i == 3: + return g(*(13, j, 19)) + elif i == 4: + return g(*(13, j, 19, 21)) + elif i == 5: + return g(7) + elif i == 6: + return g(7, *(j,)) + elif i == 7: + return g(7, *(13, j)) + elif i == 8: + return g(7, *(13, 17, j)) + elif i == 9: + return g(7, *(13, 17, j, 21)) + elif i == 10: + return g(7, 9) + elif i == 11: + return g(7, 9, *(j,)) + elif i == 12: + return g(7, 9, *(j, 17)) + elif i == 13: + return g(7, 9, *(13, j, 19)) + elif i == 14: + return g(7, 9, 11) + elif i == 15: + return g(7, 9, 11, *(j,)) + elif i == 16: + return g(7, 9, 11, *(13, j)) + elif i == 17: + return g(7, 9, 11, *(13, 17, j)) + elif i == 18: + return g(7, 9, 11, 2) + elif i == 19: + return g(7, 9, 11, 2, *(j,)) + elif i == 20: + return g(7, 9, 11, 2, *(13, j)) + else: + return 0 - def bc(j): - if j == 1: + for i in range(21): + for x in range(1): + res = interpret(f, [i, x], type_system=self.ts) + assert res == f(i, x) + + def test_conv_from_funcpbcset_to_larger(self): + def f1(): + return 7 + def f2(): + return 11 + def f3(): + return 13 + + def a(): + return f1 + def b(): return f2 - else: - return f3 + - def g(i, j): - if i == 1: - cls = a() - else: - cls = bc(j) - return cls() + def g(i): + if i == 1: + f = a() + else: + f = b() + return f() - res = interpret(g, [0, 0]) - assert res == 13 - res = interpret(g, [0, 1]) - assert res == 11 - res = interpret(g, [1, 0]) - assert res == 7 - -def test_call_special_starargs_method(): - class Star: - def __init__(self, d): - self.d = d - def meth(self, *args): - return self.d + len(args) - - def f(i, j): - s = Star(i) - return s.meth(i, j) + res = interpret(g, [0], type_system=self.ts) + assert res == 11 + res = interpret(g, [1], type_system=self.ts) + assert res == 7 + + def bc(j): + if j == 1: + return f2 + else: + return f3 - res = interpret(f, [3, 0]) - assert res == 5 + def g(i, j): + if i == 1: + cls = a() + else: + cls = bc(j) + return cls() -def test_call_star_method(): - class N: - def __init__(self, d): - self.d = d - def meth(self, a, b): - return self.d + a + b - - def f(i, j): - n = N(i) - return n.meth(*(i, j)) - - res = interpret(f, [3, 7]) - assert res == 13 - -def test_call_star_special_starargs_method(): - class N: - def __init__(self, d): - self.d = d - def meth(self, *args): - return self.d + len(args) - - def f(i, j): - n = N(i) - return n.meth(*(i, j)) + res = interpret(g, [0, 0], type_system=self.ts) + assert res == 13 + res = interpret(g, [0, 1], type_system=self.ts) + assert res == 11 + res = interpret(g, [1, 0], type_system=self.ts) + assert res == 7 + + def test_call_special_starargs_method(self): + class Star: + def __init__(self, d): + self.d = d + def meth(self, *args): + return self.d + len(args) + + def f(i, j): + s = Star(i) + return s.meth(i, j) + + res = interpret(f, [3, 0], type_system=self.ts) + assert res == 5 + + def test_call_star_method(self): + class N: + def __init__(self, d): + self.d = d + def meth(self, a, b): + return self.d + a + b + + def f(i, j): + n = N(i) + return n.meth(*(i, j)) + + res = interpret(f, [3, 7], type_system=self.ts) + assert res == 13 + + def test_call_star_special_starargs_method(self): + class N: + def __init__(self, d): + self.d = d + def meth(self, *args): + return self.d + len(args) + + def f(i, j): + n = N(i) + return n.meth(*(i, j)) - res = interpret(f, [3, 0]) - assert res == 5 + res = interpret(f, [3, 0], type_system=self.ts) + assert res == 5 def test_various_patterns_but_one_signature_method(): class A: From goden at codespeak.net Wed Mar 1 23:23:09 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Wed, 1 Mar 2006 23:23:09 +0100 (CET) Subject: [pypy-svn] r23871 - pypy/dist/pypy/rpython/rctypes/test Message-ID: <20060301222309.7036F10097@code0.codespeak.net> Author: goden Date: Wed Mar 1 23:23:01 2006 New Revision: 23871 Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: - added a note about why the full path is necessary for the _rctypes_test import Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Wed Mar 1 23:23:01 2006 @@ -274,6 +274,9 @@ class Test_structure: def test_simple_as_extension_module(self): + # Full path names follow because of strange behavior in the presence + # of an __init__.py in this test directory. When there is an + # __init__.py then the full path names appear in sys.modules import pypy.rpython.rctypes.test._rctypes_test as t0 import pypy.rpython.rctypes.test._rctypes_test as t1 assert t1 is t0 From nik at codespeak.net Wed Mar 1 23:56:32 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 1 Mar 2006 23:56:32 +0100 (CET) Subject: [pypy-svn] r23872 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20060301225632.6351110093@code0.codespeak.net> Author: nik Date: Wed Mar 1 23:56:23 2006 New Revision: 23872 Added: pypy/dist/pypy/rpython/exceptiondata.py - copied, changed from r23857, pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py - copied, changed from r23857, pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py Modified: pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/rtyper.py pypy/dist/pypy/rpython/test/test_rpbc.py pypy/dist/pypy/rpython/typesystem.py Log: (pedronis, nik) made an rpbc test working for ootype that was (accidentally) using exceptions. factored out an abstract ExceptionData class to share between the two type systems. ExceptionData of ootypesystem will need more work once we get to explicit exception tests. Modified: pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/exceptiondata.py Wed Mar 1 23:56:23 2006 @@ -4,25 +4,12 @@ from pypy.rpython.lltypesystem.lltype import \ Array, malloc, Ptr, PyObject, pyobjectptr, \ FuncType, functionptr, Signed +from pypy.rpython.exceptiondata import AbstractExceptionData from pypy.rpython.extfunctable import standardexceptions from pypy.annotation.classdef import FORCE_ATTRIBUTES_INTO_CLASSES -class ExceptionData: +class ExceptionData(AbstractExceptionData): """Public information for the code generators to help with exceptions.""" - standardexceptions = standardexceptions - - def __init__(self, rtyper): - self.make_standard_exceptions(rtyper) - # (NB. rclass identifies 'Exception' and 'object') - r_type = rclass.getclassrepr(rtyper, None) - r_instance = rclass.getinstancerepr(rtyper, None) - r_type.setup() - r_instance.setup() - self.r_exception_type = r_type - self.r_exception_value = r_instance - self.lltype_of_exception_type = r_type.lowleveltype - self.lltype_of_exception_value = r_instance.lowleveltype - def make_helpers(self, rtyper): # create helper functionptrs @@ -31,14 +18,6 @@ self.fn_pyexcclass2exc = self.make_pyexcclass2exc(rtyper) self.fn_raise_OSError = self.make_raise_OSError(rtyper) - - def make_standard_exceptions(self, rtyper): - bk = rtyper.annotator.bookkeeper - for cls in self.standardexceptions: - classdef = bk.getuniqueclassdef(cls) - rclass.getclassrepr(rtyper, classdef).setup() - - def make_exception_matcher(self, rtyper): # ll_exception_matcher(real_exception_vtable, match_exception_vtable) s_typeptr = annmodel.SomePtr(self.lltype_of_exception_type) Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Wed Mar 1 23:56:23 2006 @@ -218,8 +218,10 @@ self.classdef.classdesc.find_source_for("__init__") is not None: s_init = self.classdef.classdesc.s_get_value(self.classdef, '__init__') - mangled = mangle("__init__") - allmethods[mangled] = "__init__", s_init + if isinstance(s_init, annmodel.SomePBC): + mangled = mangle("__init__") + allmethods[mangled] = "__init__", s_init + # else: it's the __init__ of a builtin exception # # hash() support Modified: pypy/dist/pypy/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/dist/pypy/rpython/rtyper.py Wed Mar 1 23:56:23 2006 @@ -66,12 +66,7 @@ for s_primitive, lltype in annmodel.annotation_to_ll_map: r = self.getrepr(s_primitive) self.primitive_to_repr[r.lowleveltype] = r - if type_system == "lltype": - from pypy.rpython.lltypesystem.exceptiondata import ExceptionData - - self.exceptiondata = ExceptionData(self) - else: - self.exceptiondata = None + self.exceptiondata = self.type_system.exceptiondata.ExceptionData(self) try: self.seed = int(os.getenv('RTYPERSEED')) Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Wed Mar 1 23:56:23 2006 @@ -805,31 +805,31 @@ res = interpret(f, [3, 0], type_system=self.ts) assert res == 5 -def test_various_patterns_but_one_signature_method(): - class A: - def meth(self, a, b=0): - raise NotImplementedError - class B(A): - def meth(self, a, b=0): - return a+b + def test_various_patterns_but_one_signature_method(self): + class A: + def meth(self, a, b=0): + raise NotImplementedError + class B(A): + def meth(self, a, b=0): + return a+b + + class C(A): + def meth(self, a, b=0): + return a*b + def f(i): + if i == 0: + x = B() + else: + x = C() + r1 = x.meth(1) + r2 = x.meth(3, 2) + r3 = x.meth(7, b=11) + return r1+r2+r3 + res = interpret(f, [0], type_system=self.ts) + assert res == 1+3+2+7+11 + res = interpret(f, [1], type_system=self.ts) + assert res == 3*2+11*7 - class C(A): - def meth(self, a, b=0): - return a*b - def f(i): - if i == 0: - x = B() - else: - x = C() - r1 = x.meth(1) - r2 = x.meth(3, 2) - r3 = x.meth(7, b=11) - return r1+r2+r3 - res = interpret(f, [0]) - assert res == 1+3+2+7+11 - res = interpret(f, [1]) - assert res == 3*2+11*7 - def test_multiple_ll_one_hl_op(): class E(Exception): Modified: pypy/dist/pypy/rpython/typesystem.py ============================================================================== --- pypy/dist/pypy/rpython/typesystem.py (original) +++ pypy/dist/pypy/rpython/typesystem.py Wed Mar 1 23:56:23 2006 @@ -18,7 +18,7 @@ None, None, ['__doc__']) except ImportError: return None - if name in ('rclass', 'rpbc', 'rbuiltin'): + if name in ('rclass', 'rpbc', 'rbuiltin', 'exceptiondata'): mod = load(name) if mod is not None: setattr(self, name, mod) From nik at codespeak.net Thu Mar 2 00:09:34 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 00:09:34 +0100 (CET) Subject: [pypy-svn] r23874 - in pypy/dist/pypy/rpython: ootypesystem test Message-ID: <20060301230934.5D5A61008A@code0.codespeak.net> Author: nik Date: Thu Mar 2 00:09:30 2006 New Revision: 23874 Modified: pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) made another rpbc test work for ootype. fixed a failure related to exceptions, exception matching now works for ootype. Modified: pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py Thu Mar 2 00:09:30 2006 @@ -1,8 +1,17 @@ from pypy.rpython.exceptiondata import AbstractExceptionData +from pypy.rpython.ootypesystem import rclass +from pypy.rpython.annlowlevel import annotate_lowlevel_helper +from pypy.annotation import model as annmodel class ExceptionData(AbstractExceptionData): """Public information for the code generators to help with exceptions.""" def make_helpers(self, rtyper): - pass + self.fn_exception_match = self.make_exception_matcher(rtyper) + def make_exception_matcher(self, rtyper): + # ll_exception_matcher(real_exception_meta, match_exception_meta) + s_classtype = annmodel.SomeOOInstance(self.lltype_of_exception_type) + helper_graph = annotate_lowlevel_helper( + rtyper.annotator, rclass.ll_issubclass, [s_classtype, s_classtype]) + return rtyper.getcallable(helper_graph) Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Thu Mar 2 00:09:30 2006 @@ -129,9 +129,9 @@ def rtype_issubtype(self, hop): class_repr = get_type_repr(self.rtyper) vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) - return hop.gendirectcall(ll_issubtype, vmeta1, vmeta2) + return hop.gendirectcall(ll_issubclass, vmeta1, vmeta2) -def ll_issubtype(meta1, meta2): +def ll_issubclass(meta1, meta2): class1 = meta1.class_ class2 = meta2.class_ return ootype.subclassof(class1, class2) Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 2 00:09:30 2006 @@ -831,39 +831,39 @@ assert res == 3*2+11*7 -def test_multiple_ll_one_hl_op(): - class E(Exception): - pass - class A(object): - pass - class B(A): - pass - class C(object): - def method(self, x): - if x: - raise E() - else: - return A() - class D(C): - def method(self, x): - if x: - raise E() - else: - return B() - def call(x): - c = D() - c.method(x) - try: - c.method(x + 1) - except E: + def test_multiple_ll_one_hl_op(self): + class E(Exception): + pass + class A(object): + pass + class B(A): pass - c = C() - c.method(x) - try: - return c.method(x + 1) - except E: - return None - res = interpret(call, [0]) + class C(object): + def method(self, x): + if x: + raise E() + else: + return A() + class D(C): + def method(self, x): + if x: + raise E() + else: + return B() + def call(x): + c = D() + c.method(x) + try: + c.method(x + 1) + except E: + pass + c = C() + c.method(x) + try: + return c.method(x + 1) + except E: + return None + res = interpret(call, [0], type_system=self.ts) def test_multiple_pbc_with_void_attr(): class A: From nik at codespeak.net Thu Mar 2 00:25:34 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 00:25:34 +0100 (CET) Subject: [pypy-svn] r23875 - pypy/dist/pypy/rpython/test Message-ID: <20060301232534.852371008D@code0.codespeak.net> Author: nik Date: Thu Mar 2 00:25:31 2006 New Revision: 23875 Modified: pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) make more rpbc tests pass with ootype. shuffle around some tests that are not supposed to pass with ootype for now. Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 2 00:25:31 2006 @@ -865,28 +865,226 @@ return None res = interpret(call, [0], type_system=self.ts) -def test_multiple_pbc_with_void_attr(): - class A: - def _freeze_(self): - return True - a1 = A() - a2 = A() - unique = A() - unique.result = 42 - a1.value = unique - a2.value = unique - def g(a): - return a.value.result + def test_multiple_pbc_with_void_attr(self): + class A: + def _freeze_(self): + return True + a1 = A() + a2 = A() + unique = A() + unique.result = 42 + a1.value = unique + a2.value = unique + def g(a): + return a.value.result + def f(i): + if i == 1: + a = a1 + else: + a = a2 + return g(a) + res = interpret(f, [0], type_system=self.ts) + assert res == 42 + res = interpret(f, [1], type_system=self.ts) + assert res == 42 + + def test_function_or_none(self): + def h(y): + return y+84 + def g(y): + return y+42 + def f(x, y): + if x == 1: + func = g + elif x == 2: + func = h + else: + func = None + if func: + return func(y) + return -1 + res = interpret(f, [1, 100], type_system=self.ts) + assert res == 142 + res = interpret(f, [2, 100], type_system=self.ts) + assert res == 184 + res = interpret(f, [3, 100], type_system=self.ts) + assert res == -1 + + def test_pbc_getattr_conversion(self): + fr1 = Freezing() + fr2 = Freezing() + fr3 = Freezing() + fr1.value = 10 + fr2.value = 5 + fr3.value = 2.5 + def pick12(i): + if i > 0: + return fr1 + else: + return fr2 + def pick23(i): + if i > 5: + return fr2 + else: + return fr3 + def f(i): + x = pick12(i) + y = pick23(i) + return x.value, y.value + for i in [0, 5, 10]: + res = interpret(f, [i], type_system=self.ts) + assert type(res.item0) is int # precise + assert type(res.item1) is float + assert res.item0 == f(i)[0] + assert res.item1 == f(i)[1] + + def test_pbc_getattr_conversion_with_classes(self): + class base: pass + class fr1(base): pass + class fr2(base): pass + class fr3(base): pass + fr1.value = 10 + fr2.value = 5 + fr3.value = 2.5 + def pick12(i): + if i > 0: + return fr1 + else: + return fr2 + def pick23(i): + if i > 5: + return fr2 + else: + return fr3 + def f(i): + x = pick12(i) + y = pick23(i) + return x.value, y.value + for i in [0, 5, 10]: + res = interpret(f, [i], type_system=self.ts) + assert type(res.item0) is int # precise + assert type(res.item1) is float + assert res.item0 == f(i)[0] + assert res.item1 == f(i)[1] + +def test_multiple_specialized_functions(): + def myadder(x, y): # int,int->int or str,str->str + return x+y + def myfirst(x, y): # int,int->int or str,str->str + return x + def mysecond(x, y): # int,int->int or str,str->str + return y + myadder._annspecialcase_ = 'specialize:argtype(0)' + myfirst._annspecialcase_ = 'specialize:argtype(0)' + mysecond._annspecialcase_ = 'specialize:argtype(0)' + def f(i): + if i == 0: + g = myfirst + elif i == 1: + g = mysecond + else: + g = myadder + s = g("hel", "lo") + n = g(40, 2) + return len(s) * n + for i in range(3): + res = interpret(f, [i]) + assert res == f(i) + +def test_specialized_method_of_frozen(): + class space: + def __init__(self, tag): + self.tag = tag + def wrap(self, x): + if isinstance(x, int): + return self.tag + '< %d >' % x + else: + return self.tag + x + wrap._annspecialcase_ = 'specialize:argtype(1)' + space1 = space("tag1:") + space2 = space("tag2:") def f(i): if i == 1: - a = a1 + sp = space1 else: - a = a2 - return g(a) - res = interpret(f, [0]) - assert res == 42 + sp = space2 + w1 = sp.wrap('hello') + w2 = sp.wrap(42) + return w1 + w2 res = interpret(f, [1]) - assert res == 42 + assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' + res = interpret(f, [0]) + assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + +def test_call_from_list(): + def f0(n): return n+200 + def f1(n): return n+192 + def f2(n): return n+46 + def f3(n): return n+2987 + def f4(n): return n+217 + lst = [f0, f1, f2, f3, f4] + def f(i, n): + return lst[i](n) + for i in range(5): + res = interpret(f, [i, 1000]) + assert res == f(i, 1000) + +def test_precise_method_call_1(): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): + pass + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth only, using the default argument + result2 = C().meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234]) + assert res == f(i, 1234) + +def test_precise_method_call_2(): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): + def meth(self, x=5): + return x+3 + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth and C.meth, using the default argument + if i > 0: + x = C() + else: + x = A() + result2 = x.meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234]) + assert res == f(i, 1234) + + +# We don't care about the following test_hlinvoke tests working on +# ootype. Maybe later. This kind of thing is only used in rdict +# anyway, that will probably have a different kind of implementation +# in ootype. def test_hlinvoke_simple(): def f(a,b): @@ -975,7 +1173,6 @@ res = interp.eval_graph(ll_h_graph, [None, r_f.convert_desc(f2desc), 3]) assert res == 1 - def test_hlinvoke_hltype(): class A(object): def __init__(self, v): @@ -1136,194 +1333,6 @@ res = interp.eval_graph(ll_h_graph, [None, c_f, c_a]) assert typeOf(res) == A_repr.lowleveltype -def test_function_or_none(): - def h(y): - return y+84 - def g(y): - return y+42 - def f(x, y): - d = {1: g, 2:h} - func = d.get(x, None) - if func: - return func(y) - return -1 - res = interpret(f, [1, 100]) - assert res == 142 - res = interpret(f, [2, 100]) - assert res == 184 - res = interpret(f, [3, 100]) - assert res == -1 - -def test_pbc_getattr_conversion(): - fr1 = Freezing() - fr2 = Freezing() - fr3 = Freezing() - fr1.value = 10 - fr2.value = 5 - fr3.value = 2.5 - def pick12(i): - if i > 0: - return fr1 - else: - return fr2 - def pick23(i): - if i > 5: - return fr2 - else: - return fr3 - def f(i): - x = pick12(i) - y = pick23(i) - return x.value, y.value - for i in [0, 5, 10]: - res = interpret(f, [i]) - assert type(res.item0) is int # precise - assert type(res.item1) is float - assert res.item0 == f(i)[0] - assert res.item1 == f(i)[1] - -def test_pbc_getattr_conversion_with_classes(): - class base: pass - class fr1(base): pass - class fr2(base): pass - class fr3(base): pass - fr1.value = 10 - fr2.value = 5 - fr3.value = 2.5 - def pick12(i): - if i > 0: - return fr1 - else: - return fr2 - def pick23(i): - if i > 5: - return fr2 - else: - return fr3 - def f(i): - x = pick12(i) - y = pick23(i) - return x.value, y.value - for i in [0, 5, 10]: - res = interpret(f, [i]) - assert type(res.item0) is int # precise - assert type(res.item1) is float - assert res.item0 == f(i)[0] - assert res.item1 == f(i)[1] - -def test_multiple_specialized_functions(): - def myadder(x, y): # int,int->int or str,str->str - return x+y - def myfirst(x, y): # int,int->int or str,str->str - return x - def mysecond(x, y): # int,int->int or str,str->str - return y - myadder._annspecialcase_ = 'specialize:argtype(0)' - myfirst._annspecialcase_ = 'specialize:argtype(0)' - mysecond._annspecialcase_ = 'specialize:argtype(0)' - def f(i): - if i == 0: - g = myfirst - elif i == 1: - g = mysecond - else: - g = myadder - s = g("hel", "lo") - n = g(40, 2) - return len(s) * n - for i in range(3): - res = interpret(f, [i]) - assert res == f(i) - -def test_specialized_method_of_frozen(): - class space: - def __init__(self, tag): - self.tag = tag - def wrap(self, x): - if isinstance(x, int): - return self.tag + '< %d >' % x - else: - return self.tag + x - wrap._annspecialcase_ = 'specialize:argtype(1)' - space1 = space("tag1:") - space2 = space("tag2:") - def f(i): - if i == 1: - sp = space1 - else: - sp = space2 - w1 = sp.wrap('hello') - w2 = sp.wrap(42) - return w1 + w2 - res = interpret(f, [1]) - assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' - res = interpret(f, [0]) - assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' - -def test_call_from_list(): - def f0(n): return n+200 - def f1(n): return n+192 - def f2(n): return n+46 - def f3(n): return n+2987 - def f4(n): return n+217 - lst = [f0, f1, f2, f3, f4] - def f(i, n): - return lst[i](n) - for i in range(5): - res = interpret(f, [i, 1000]) - assert res == f(i, 1000) - -def test_precise_method_call_1(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - pass - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth only, using the default argument - result2 = C().meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) - -def test_precise_method_call_2(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - def meth(self, x=5): - return x+3 - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth and C.meth, using the default argument - if i > 0: - x = C() - else: - x = A() - result2 = x.meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) - class TestLltype(BaseTestRPBC): From goden at codespeak.net Thu Mar 2 00:55:14 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Thu, 2 Mar 2006 00:55:14 +0100 (CET) Subject: [pypy-svn] r23877 - in pypy/dist/pypy: annotation rpython/rctypes rpython/rctypes/test Message-ID: <20060301235514.4BF9C1008D@code0.codespeak.net> Author: goden Date: Thu Mar 2 00:55:09 2006 New Revision: 23877 Added: pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/rpython/rctypes/implementation.py pypy/dist/pypy/rpython/rctypes/test/test_rarray.py pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: - (arigo, goden) removed the redundant Test_rarray class from test_rctypes. cleaned up the test_rarray module a bit. new rprimitive module for annotating unmodified ctypes objects. disabled the previous annotation of ctypes objects for primitive types. added a lookup to the extregistry in the unaryop annotation module to find the types of attributes of ctypes objects. skipped existing rctypes tests while the ctypes primitive annotation is reworked to use the rpython.extregistry module. now importing the ctypes types instead of customized rctypes versions. Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Thu Mar 2 00:55:09 2006 @@ -13,6 +13,7 @@ from pypy.annotation import builtin from pypy.annotation.binaryop import _clone ## XXX where to put this? +from pypy.rpython import extregistry # convenience only! def immutablevalue(x): @@ -644,7 +645,12 @@ "%r object has no attribute %r" % ( cto.knowntype, s_attr.const)) else: - atype = cto.knowntype._fields_def_[attr] + if extregistry.is_registered_type(cto.knowntype): + entry = extregistry.lookup_type(cto.knowntype) + s_value = entry.fields_s[attr] + return s_value + else: + atype = cto.knowntype._fields_def_[attr] try: return atype.annotator_type except AttributeError: Modified: pypy/dist/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/implementation.py (original) +++ pypy/dist/pypy/rpython/rctypes/implementation.py Thu Mar 2 00:55:09 2006 @@ -22,24 +22,25 @@ # Importing for side effect of registering types with extregistry import pypy.rpython.rctypes.rarray +import pypy.rpython.rctypes.rprimitive # ctypes_annotation_list contains various attributes that # are used by the pypy annotation. ctypes_annotation_list = [ - (c_char, Char, None), - (c_byte, Signed, None), - (c_ubyte, Unsigned, None), - (c_short, Signed, None), - (c_ushort, Unsigned, None), - (c_int, Signed, None), - (c_uint, Unsigned, None), - (c_long, Signed, None), - (c_ulong, Unsigned, None), - (c_longlong, SignedLongLong, None), - (c_ulonglong, UnsignedLongLong, None), - (c_float, Float, None), - (c_double, Float, None), +# (c_char, Char, None), +# (c_byte, Signed, None), +# (c_ubyte, Unsigned, None), +# (c_short, Signed, None), +# (c_ushort, Unsigned, None), +# (c_int, Signed, None), +# (c_uint, Unsigned, None), +# (c_long, Signed, None), +# (c_ulong, Unsigned, None), +# (c_longlong, SignedLongLong, None), +# (c_ulonglong, UnsignedLongLong, None), +# (c_float, Float, None), +# (c_double, Float, None), (c_char_p, None, staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), (POINTER(c_char), None, Added: pypy/dist/pypy/rpython/rctypes/rprimitive.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/rprimitive.py Thu Mar 2 00:55:09 2006 @@ -0,0 +1,46 @@ +from ctypes import c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint +from ctypes import c_long, c_ulong, c_longlong, c_ulonglong, c_float +from ctypes import c_double, c_char_p +from pypy.annotation import model as annmodel +from pypy.rpython import extregistry +from pypy.rpython.rmodel import Repr +from pypy.rpython.lltypesystem import lltype +from pypy.annotation.pairtype import pairtype +from pypy.rpython.rmodel import IntegerRepr + +ctypes_annotation_list = [ + (c_char, lltype.Char), + (c_byte, lltype.Signed), + (c_ubyte, lltype.Unsigned), + (c_short, lltype.Signed), + (c_ushort, lltype.Unsigned), + (c_int, lltype.Signed), + (c_uint, lltype.Unsigned), + (c_long, lltype.Signed), + (c_ulong, lltype.Unsigned), + (c_longlong, lltype.SignedLongLong), + (c_ulonglong, lltype.UnsignedLongLong), + (c_float, lltype.Float), + (c_double, lltype.Float), +] + +def do_register(the_type, ll_type): + def annotation_function(s_arg): + return annmodel.SomeCTypesObject(the_type, + annmodel.SomeCTypesObject.OWNSMEMORY) + + extregistry.register_value(the_type, + compute_result_annotation=annotation_function) + entry = extregistry.register_type(the_type) + entry.fields_s = {'value': annmodel.lltype_to_annotation(ll_type)} + +for the_type, ll_type in ctypes_annotation_list: + do_register(the_type, ll_type) + +#extregistry.register_type(ArrayType, +# compute_annotation=arraytype_compute_annotation, +# specialize_call=arraytype_specialize_call) + +#def arraytype_get_repr(rtyper, s_array): +# return ArrayRepr(rtyper, s_array.knowntype) +#extregistry.register_metatype(ArrayType, get_repr=arraytype_get_repr) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Thu Mar 2 00:55:09 2006 @@ -15,10 +15,7 @@ except ImportError: py.test.skip("this test needs ctypes installed") -from pypy.rpython.rctypes import cdll, c_char_p, c_int, c_char, \ - c_char, c_byte, c_ubyte, c_short, c_ushort, c_uint,\ - c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ - POINTER, Structure, byref, ARRAY +from ctypes import c_int, ARRAY, POINTER c_int_10 = ARRAY(c_int,10) c_int_p_test = POINTER(c_int) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Thu Mar 2 00:55:09 2006 @@ -43,6 +43,8 @@ py.test.skip("this test needs ctypes installed") +py.test.skip("these tests are broken while the ctypes primitive types are ported to use the extregistry") + from pypy.rpython.rctypes import cdll, c_char_p, c_int, c_char, \ c_char, c_byte, c_ubyte, c_short, c_ushort, c_uint,\ c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ @@ -243,7 +245,6 @@ s.y = y return s - class Test_rctypes: def test_simple(self): @@ -469,84 +470,3 @@ fn = compile( py_test_compile_pointer, [ int, int ] ) res = fn( -42, 42 ) assert res == -42 - - -class Test_array: - - def test_annotate_array(self): - a = RPythonAnnotator() - s = a.build_types(py_test_annotate_array, []) - assert s.knowntype == c_int_10 - - if conftest.option.view: - a.translator.view() - - def test_annotate_array_access(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_content, []) - assert s.knowntype == int - - if conftest.option.view: - t.view() - - def test_annotate_pointer_access_as_array(self): - """ - Make sure that pointers work the same way as arrays, for - ctypes compatibility. - - :Note: This works because pointer and array classes both - have a _type_ attribute, that contains the type of the - object pointed to or in the case of an array the element type. - """ - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_pointer_content, []) - assert s.knowntype == int - #d#t.view() - - def test_annotate_array_slice_access(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_slice_content, []) - #d#t.view() - #d#print "v90:", s, type(s) - assert s.knowntype == list - s.listdef.listitem.s_value.knowntype == int - - def test_annotate_array_access_variable(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_content_variable_index, []) - assert s.knowntype == int - #t#t.view() - - def test_annotate_array_access_index_error_on_positive_index(self): - t = TranslationContext() - a = t.buildannotator() - - py.test.raises(IndexError, "s = a.build_types(py_test_annotate_array_content_index_error_on_positive_index,[])") - - def test_annotate_array_access_index_error_on_negative_index(self): - t = TranslationContext() - a = t.buildannotator() - - py.test.raises(IndexError, "s = a.build_types(py_test_annotate_array_content_index_error_on_negative_index,[])") - - def test_specialize_array(self): - res = interpret(py_test_annotate_array, []) - c_data = res.c_data - assert c_data[0] == 0 - assert c_data[9] == 0 - py.test.raises(IndexError, "c_data[10]") - py.test.raises(TypeError, "len(c_data)") - - def test_specialize_array_access(self): - def test_specialize_array_access(): - my_array = c_int_10() - my_array[0] = 1 - - return my_array[0] - - res = interpret(test_specialize_array_access, []) - assert res == 1 Added: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Thu Mar 2 00:55:09 2006 @@ -0,0 +1,36 @@ +""" +Test the rctypes implementation. +""" + +import py.test +from pypy.annotation.annrpython import RPythonAnnotator +from pypy.translator.translator import TranslationContext +from pypy.translator.c.test.test_genc import compile +from pypy.annotation.model import SomeCTypesObject, SomeObject +from pypy import conftest +import sys +from pypy.rpython.test.test_llinterp import interpret + +from ctypes import c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint +from ctypes import c_long, c_ulong, c_longlong, c_ulonglong, c_float +from ctypes import c_double, c_char_p + +class Test_annotation: + def test_simple(self): + res = c_int(42) + assert res.value == 42 + + def test_annotate_c_int(self): + def func(): + res = c_int(42) + + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == int + + if conftest.option.view: + t.view() From mwh at codespeak.net Thu Mar 2 00:57:31 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 2 Mar 2006 00:57:31 +0100 (CET) Subject: [pypy-svn] r23880 - pypy/dist/pypy/translator/c/src Message-ID: <20060301235731.694251008D@code0.codespeak.net> Author: mwh Date: Thu Mar 2 00:57:28 2006 New Revision: 23880 Modified: pypy/dist/pypy/translator/c/src/support.h Log: don't duplicate the declaration of PyTuple_Pack (breaks on 2.5 with the Py_ssize_t changes) Modified: pypy/dist/pypy/translator/c/src/support.h ============================================================================== --- pypy/dist/pypy/translator/c/src/support.h (original) +++ pypy/dist/pypy/translator/c/src/support.h Thu Mar 2 00:57:28 2006 @@ -33,7 +33,9 @@ PyObject * gencfunc_descr_get(PyObject *func, PyObject *obj, PyObject *type); PyObject* PyList_Pack(int n, ...); PyObject* PyDict_Pack(int n, ...); +#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ PyObject* PyTuple_Pack(int n, ...); +#endif #if PY_VERSION_HEX >= 0x02030000 /* 2.3 */ # define PyObject_GetItem1 PyObject_GetItem # define PyObject_SetItem1 PyObject_SetItem From nik at codespeak.net Thu Mar 2 01:02:08 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 01:02:08 +0100 (CET) Subject: [pypy-svn] r23881 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20060302000208.B703A10094@code0.codespeak.net> Author: nik Date: Thu Mar 2 01:02:04 2006 New Revision: 23881 Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py pypy/dist/pypy/rpython/ootypesystem/rpbc.py pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) made specialized functions work for ootype by factoring out an abstract FunctionsPBCRepr. fixed a test about frozen methods that wasn't testing what it thought it was (no _freeze_ method!). discovered by accident a different failing tests for specialized methods with ootype, disabled for now. Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rpbc.py Thu Mar 2 01:02:04 2006 @@ -11,9 +11,10 @@ from pypy.rpython import robject from pypy.rpython import rtuple from pypy.rpython.rpbc import samesig,\ - commonbase, allattributenames, adjust_shape, FunctionsPBCRepr, \ + commonbase, allattributenames, adjust_shape, \ AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr, \ - AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr + AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ + AbstractFunctionsPBCRepr from pypy.rpython.lltypesystem import rclass from pypy.tool.sourcetools import has_varargs @@ -54,6 +55,21 @@ # ____________________________________________________________ +class FunctionsPBCRepr(AbstractFunctionsPBCRepr): + """Representation selected for a PBC of function(s).""" + + def setup_specfunc(self): + fields = [] + for row in self.uniquerows: + fields.append((row.attrname, row.fntype)) + return Ptr(Struct('specfunc', *fields)) + + def create_specfunc(self): + return malloc(self.lowleveltype.TO, immortal=True) + + def get_specfunc_row(self, llop, v, c_rowname, resulttype): + return llop.genop('getfield', [v, c_rowname], resulttype=resulttype) + class MethodsPBCRepr(AbstractMethodsPBCRepr): """Representation selected for a PBC of the form {func: classdef...}. It assumes that all the methods come from the same name in a base Modified: pypy/dist/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rpbc.py Thu Mar 2 01:02:04 2006 @@ -1,6 +1,7 @@ from pypy.rpython.rmodel import CanBeNull, Repr, inputconst from pypy.rpython.rpbc import AbstractClassesPBCRepr, AbstractMethodsPBCRepr, \ - AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr + AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ + AbstractFunctionsPBCRepr from pypy.rpython.rclass import rtype_new_instance, getinstancerepr from pypy.rpython.rpbc import get_concrete_calltable from pypy.rpython import callparse @@ -12,6 +13,22 @@ from pypy.annotation.pairtype import pairtype import types + +class FunctionsPBCRepr(AbstractFunctionsPBCRepr): + """Representation selected for a PBC of function(s).""" + + def setup_specfunc(self): + fields = {} + for row in self.uniquerows: + fields[row.attrname] = row.fntype + return ootype.Instance('specfunc', ootype.ROOT, fields) + + def create_specfunc(self): + return ootype.new(self.lowleveltype) + + def get_specfunc_row(self, llop, v, c_rowname, resulttype): + return llop.genop('oogetfield', [v, c_rowname], resulttype=resulttype) + class ClassesPBCRepr(AbstractClassesPBCRepr): def rtype_simple_call(self, hop): Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Thu Mar 2 01:02:04 2006 @@ -26,7 +26,7 @@ if sample.overridden: getRepr = OverriddenFunctionPBCRepr else: - getRepr = FunctionsPBCRepr + getRepr = rtyper.type_system.rpbc.FunctionsPBCRepr else: getRepr = getFrozenPBCRepr elif issubclass(kind, description.ClassDesc): @@ -155,7 +155,7 @@ return concretetable, uniquerows -class FunctionsPBCRepr(CanBeNull, Repr): +class AbstractFunctionsPBCRepr(CanBeNull, Repr): """Representation selected for a PBC of function(s).""" def __init__(self, rtyper, s_pbc): @@ -177,10 +177,7 @@ # several functions, each with several specialized variants. # each function becomes a pointer to a Struct containing # pointers to its variants. - fields = [] - for row in uniquerows: - fields.append((row.attrname, row.fntype)) - self.lowleveltype = Ptr(Struct('specfunc', *fields)) + self.lowleveltype = self.setup_specfunc() self.funccache = {} def get_s_callable(self): @@ -230,7 +227,7 @@ result = llfn # from the loop above else: # build a Struct with all the values collected in 'llfns' - result = malloc(self.lowleveltype.TO, immortal=True) + result = self.create_specfunc() for attrname, llfn in llfns.items(): setattr(result, attrname, llfn) self.funccache[funcdesc] = result @@ -267,7 +264,7 @@ # 'v' is a Struct pointer, read the corresponding field row = self.concretetable[shape, index] cname = inputconst(Void, row.attrname) - return llop.genop('getfield', [v, cname], resulttype = row.fntype) + return self.get_specfunc_row(llop, v, cname, row.fntype) def get_unique_llfn(self): # try to build a unique low-level function. Avoid to use @@ -320,7 +317,7 @@ v = hop.genop('indirect_call', vlist, resulttype = rresult) return hop.llops.convertvar(v, rresult, hop.r_result) -class __extend__(pairtype(FunctionsPBCRepr, FunctionsPBCRepr)): +class __extend__(pairtype(AbstractFunctionsPBCRepr, AbstractFunctionsPBCRepr)): def convert_from_to((r_fpbc1, r_fpbc2), v, llops): # this check makes sense because both source and dest repr are FunctionsPBCRepr if r_fpbc1.lowleveltype == r_fpbc2.lowleveltype: Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 2 01:02:04 2006 @@ -967,54 +967,81 @@ assert res.item0 == f(i)[0] assert res.item1 == f(i)[1] -def test_multiple_specialized_functions(): - def myadder(x, y): # int,int->int or str,str->str - return x+y - def myfirst(x, y): # int,int->int or str,str->str - return x - def mysecond(x, y): # int,int->int or str,str->str - return y - myadder._annspecialcase_ = 'specialize:argtype(0)' - myfirst._annspecialcase_ = 'specialize:argtype(0)' - mysecond._annspecialcase_ = 'specialize:argtype(0)' - def f(i): - if i == 0: - g = myfirst - elif i == 1: - g = mysecond - else: - g = myadder - s = g("hel", "lo") - n = g(40, 2) - return len(s) * n - for i in range(3): - res = interpret(f, [i]) - assert res == f(i) - -def test_specialized_method_of_frozen(): - class space: - def __init__(self, tag): - self.tag = tag - def wrap(self, x): - if isinstance(x, int): - return self.tag + '< %d >' % x + def test_multiple_specialized_functions(self): + def myadder(x, y): # int,int->int or str,str->str + return x+y + def myfirst(x, y): # int,int->int or str,str->str + return x + def mysecond(x, y): # int,int->int or str,str->str + return y + myadder._annspecialcase_ = 'specialize:argtype(0)' + myfirst._annspecialcase_ = 'specialize:argtype(0)' + mysecond._annspecialcase_ = 'specialize:argtype(0)' + def f(i): + if i == 0: + g = myfirst + elif i == 1: + g = mysecond else: - return self.tag + x - wrap._annspecialcase_ = 'specialize:argtype(1)' - space1 = space("tag1:") - space2 = space("tag2:") - def f(i): - if i == 1: - sp = space1 - else: - sp = space2 - w1 = sp.wrap('hello') - w2 = sp.wrap(42) - return w1 + w2 - res = interpret(f, [1]) - assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' - res = interpret(f, [0]) - assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + g = myadder + s = g("hel", "lo") + n = g(40, 2) + return len(s) * n + for i in range(3): + res = interpret(f, [i], type_system=self.ts) + assert res == f(i) + + def test_specialized_method_of_frozen(self): + class space: + def _freeze_(self): + return True + def __init__(self, tag): + self.tag = tag + def wrap(self, x): + if isinstance(x, int): + return self.tag + '< %d >' % x + else: + return self.tag + x + wrap._annspecialcase_ = 'specialize:argtype(1)' + space1 = space("tag1:") + space2 = space("tag2:") + def f(i): + if i == 1: + sp = space1 + else: + sp = space2 + w1 = sp.wrap('hello') + w2 = sp.wrap(42) + return w1 + w2 + res = interpret(f, [1], type_system=self.ts) + assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + + def DONT_test_specialized_method(self): + class A: + def __init__(self, tag): + self.tag = tag + def wrap(self, x): + if isinstance(x, int): + return self.tag + '< %d >' % x + else: + return self.tag + x + wrap._annspecialcase_ = 'specialize:argtype(1)' + a1 = A("tag1:") + a2 = A("tag2:") + def f(i): + if i == 1: + sp = a1 + else: + sp = a2 + w1 = sp.wrap('hello') + w2 = sp.wrap(42) + return w1 + w2 + res = interpret(f, [1], type_system=self.ts) + assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' def test_call_from_list(): def f0(n): return n+200 From nik at codespeak.net Thu Mar 2 01:55:30 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 01:55:30 +0100 (CET) Subject: [pypy-svn] r23886 - in pypy/dist/pypy/rpython: ootypesystem test Message-ID: <20060302005530.AA31A10093@code0.codespeak.net> Author: nik Date: Thu Mar 2 01:55:26 2006 New Revision: 23886 Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) made specialized methods work for ootype with surprisingly little hair-pulling. all method names are now mangled, so that all specialized variants have distinct names (even if there is only one variant). Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Thu Mar 2 01:55:26 2006 @@ -259,9 +259,9 @@ # get method implementation from pypy.rpython.ootypesystem.rpbc import MethodImplementations methimpls = MethodImplementations.get(self.rtyper, s_value) - m = methimpls.get_impl(mangled, methdesc) - - methods[mangled] = m + m_impls = methimpls.get_impl(mangled, methdesc) + + methods.update(m_impls) for classdef in self.classdef.getmro(): Modified: pypy/dist/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rpbc.py Thu Mar 2 01:55:26 2006 @@ -73,21 +73,21 @@ rtype_call_args = rtype_simple_call +def row_method_name(methodname, rowname): + return "%s_%s" % (methodname, rowname) + class MethodImplementations(object): def __init__(self, rtyper, methdescs): samplemdesc = methdescs.iterkeys().next() concretetable, uniquerows = get_concrete_calltable(rtyper, samplemdesc.funcdesc.getcallfamily()) - self._uniquerows = uniquerows - if len(uniquerows) == 1: - row = uniquerows[0] + self.row_mapping = {} + for row in uniquerows: sample_as_static_meth = row.itervalues().next() SM = ootype.typeOf(sample_as_static_meth) M = ootype.Meth(SM.ARGS[1:], SM.RESULT) # cut self - self.lowleveltype = M - else: - XXX_later + self.row_mapping[row.attrname] = row, M def get(rtyper, s_pbc): lst = list(s_pbc.descriptions) @@ -102,18 +102,25 @@ get = staticmethod(get) def get_impl(self, name, methdesc): - M = self.lowleveltype - if methdesc is None: - return ootype.meth(M, _name=name, abstract=True) - else: - impl_graph = self._uniquerows[0][methdesc.funcdesc].graph - return ootype.meth(M, _name=name, graph=impl_graph) - + impls = {} + for rowname, (row, M) in self.row_mapping.iteritems(): + if methdesc is None: + m = ootype.meth(M, _name=name, abstract=True) + else: + impl_graph = row[methdesc.funcdesc].graph + m = ootype.meth(M, _name=name, graph=impl_graph) + derived_name = row_method_name(name, rowname) + impls[derived_name] = m + return impls + class MethodsPBCRepr(AbstractMethodsPBCRepr): def __init__(self, rtyper, s_pbc): AbstractMethodsPBCRepr.__init__(self, rtyper, s_pbc) + sampledesc = s_pbc.descriptions.iterkeys().next() + self.concretetable, _ = get_concrete_calltable(rtyper, + sampledesc.funcdesc.getcallfamily()) def rtype_simple_call(self, hop): return self.call("simple_call", hop) @@ -138,7 +145,9 @@ rresult = callparse.getrresult(self.rtyper, anygraph) hop.exception_is_here() mangled = mangle(self.methodname) - cname = hop.inputconst(ootype.Void, mangled) + row = self.concretetable[shape, index] + derived_mangled = row_method_name(mangled, row.attrname) + cname = hop.inputconst(ootype.Void, derived_mangled) v = hop.genop("oosend", [cname]+vlist, resulttype=rresult) return hop.llops.convertvar(v, rresult, hop.r_result) Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 2 01:55:26 2006 @@ -1018,7 +1018,7 @@ res = interpret(f, [0], type_system=self.ts) assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' - def DONT_test_specialized_method(self): + def test_specialized_method(self): class A: def __init__(self, tag): self.tag = tag From mwh at codespeak.net Thu Mar 2 02:11:12 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 2 Mar 2006 02:11:12 +0100 (CET) Subject: [pypy-svn] r23887 - pypy/dist/pypy/translator Message-ID: <20060302011112.929341009A@code0.codespeak.net> Author: mwh Date: Thu Mar 2 02:11:05 2006 New Revision: 23887 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: DO NOT use Exception as the prototypical old-style class, because with python svn head, it ain't an old-style class. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Thu Mar 2 02:11:05 2006 @@ -203,7 +203,7 @@ self.builtin_ids = dict( [ (id(value), bltinstub(key)) for key, value in __builtin__.__dict__.items() - if callable(value) and type(value) not in [type(Exception), type] ] ) + if callable(value) and type(value) not in [types.ClassType, type] ] ) self.space = FlowObjSpace() # for introspection @@ -748,7 +748,7 @@ return 'space.w_%s' % cls.__name__ if not isinstance(cls, type): - assert type(cls) is type(Exception) + assert type(cls) is types.ClassType # do *not* change metaclass, but leave the # decision to what PyPy thinks is correct. # metaclass = 'space.w_classobj' @@ -824,7 +824,7 @@ str: 'space.w_str', float: 'space.w_float', slice: 'space.w_slice', - type(Exception()): (eval_helper, 'InstanceType', 'types.InstanceType'), + types.InstanceType: (eval_helper, 'InstanceType', 'types.InstanceType'), type: 'space.w_type', complex: (eval_helper, 'complex', 'types.ComplexType'), unicode:'space.w_unicode', From nik at codespeak.net Thu Mar 2 02:11:37 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 02:11:37 +0100 (CET) Subject: [pypy-svn] r23888 - pypy/dist/pypy/rpython/test Message-ID: <20060302011137.F0A30100A0@code0.codespeak.net> Author: nik Date: Thu Mar 2 02:11:30 2006 New Revision: 23888 Modified: pypy/dist/pypy/rpython/test/test_rpbc.py Log: (pedronis, nik) yay! all tests in test_rpbc now pass for ootype. most of the basics of ootypesystem are now there. next up is running tests in test_rclass on ootype. Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 2 02:11:30 2006 @@ -1043,7 +1043,61 @@ res = interpret(f, [0], type_system=self.ts) assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + def test_precise_method_call_1(self): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): + pass + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth only, using the default argument + result2 = C().meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234], type_system=self.ts) + assert res == f(i, 1234) + + def test_precise_method_call_2(self): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): + def meth(self, x=5): + return x+3 + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth and C.meth, using the default argument + if i > 0: + x = C() + else: + x = A() + result2 = x.meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234], type_system=self.ts) + assert res == f(i, 1234) + + def test_call_from_list(): + # Don't test with ootype, since it doesn't support lists in a + # coherent way yet. def f0(n): return n+200 def f1(n): return n+192 def f2(n): return n+46 @@ -1056,57 +1110,6 @@ res = interpret(f, [i, 1000]) assert res == f(i, 1000) -def test_precise_method_call_1(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - pass - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth only, using the default argument - result2 = C().meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) - -def test_precise_method_call_2(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - def meth(self, x=5): - return x+3 - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth and C.meth, using the default argument - if i > 0: - x = C() - else: - x = A() - result2 = x.meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) - # We don't care about the following test_hlinvoke tests working on # ootype. Maybe later. This kind of thing is only used in rdict From pedronis at codespeak.net Thu Mar 2 02:39:15 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 2 Mar 2006 02:39:15 +0100 (CET) Subject: [pypy-svn] r23891 - in pypy/dist/pypy: jit rpython Message-ID: <20060302013915.8708610082@code0.codespeak.net> Author: pedronis Date: Thu Mar 2 02:39:09 2006 New Revision: 23891 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/rpython/rtyper.py pypy/dist/pypy/rpython/typesystem.py Log: fix breaking of test_hint_timeshift. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Thu Mar 2 02:39:09 2006 @@ -12,6 +12,8 @@ class HintTypeSystem(TypeSystem): name = "hinttypesystem" + offers_exceptiondata = False + def perform_normalizations(self, rtyper): pass # for now @@ -27,7 +29,7 @@ return hs.concretetype class HintRTyper(RPythonTyper): - + def __init__(self, hannotator, timeshifter): RPythonTyper.__init__(self, hannotator, type_system=HintTypeSystem.instance) Modified: pypy/dist/pypy/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/dist/pypy/rpython/rtyper.py Thu Mar 2 02:39:09 2006 @@ -66,7 +66,10 @@ for s_primitive, lltype in annmodel.annotation_to_ll_map: r = self.getrepr(s_primitive) self.primitive_to_repr[r.lowleveltype] = r - self.exceptiondata = self.type_system.exceptiondata.ExceptionData(self) + if self.type_system.offers_exceptiondata: + self.exceptiondata = self.type_system.exceptiondata.ExceptionData(self) + else: + self.exceptiondata = None try: self.seed = int(os.getenv('RTYPERSEED')) Modified: pypy/dist/pypy/rpython/typesystem.py ============================================================================== --- pypy/dist/pypy/rpython/typesystem.py (original) +++ pypy/dist/pypy/rpython/typesystem.py Thu Mar 2 02:39:09 2006 @@ -10,6 +10,8 @@ class TypeSystem(object): __metaclass__ = extendabletype + offers_exceptiondata = True + def __getattr__(self, name): """Lazy import to avoid circular dependencies.""" def load(modname): From stuart at codespeak.net Thu Mar 2 02:56:54 2006 From: stuart at codespeak.net (stuart at codespeak.net) Date: Thu, 2 Mar 2006 02:56:54 +0100 (CET) Subject: [pypy-svn] r23893 - in pypy/dist: lib-python/modified-2.4.1 pypy/interpreter pypy/interpreter/astcompiler pypy/interpreter/pyparser pypy/interpreter/pyparser/data pypy/interpreter/pyparser/test/samples pypy/interpreter/test pypy/tool Message-ID: <20060302015654.E27C81008A@code0.codespeak.net> Author: stuart Date: Thu Mar 2 02:56:53 2006 New Revision: 23893 Added: pypy/dist/lib-python/modified-2.4.1/__future__.py - copied, changed from r23743, pypy/dist/lib-python/2.4.1/__future__.py pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a_with pypy/dist/pypy/tool/__future__.py Modified: pypy/dist/pypy/interpreter/astcompiler/consts.py pypy/dist/pypy/interpreter/astcompiler/future.py pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/pycompiler.py pypy/dist/pypy/interpreter/pyparser/astbuilder.py pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a pypy/dist/pypy/interpreter/pyparser/pythonparse.py pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py pypy/dist/pypy/interpreter/test/test_syntax.py Log: Arre, Ale, Stuart Williams Implemented 'from __future__ import with_statement'. Unfortunately this increased the entropy in the compiler mess. When this feature is found we restart compilation with an alternate grammar. Modified: pypy/dist/pypy/interpreter/astcompiler/consts.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/consts.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/consts.py Thu Mar 2 02:56:53 2006 @@ -19,3 +19,4 @@ CO_GENERATOR = 0x0020 CO_GENERATOR_ALLOWED = 0x1000 CO_FUTURE_DIVISION = 0x2000 +CO_FUTURE_WITH_STATEMENT = 0x8000 Modified: pypy/dist/pypy/interpreter/astcompiler/future.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/future.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/future.py Thu Mar 2 02:56:53 2006 @@ -15,7 +15,7 @@ class FutureParser(ast.ASTVisitor): - features = ("nested_scopes", "generators", "division") + features = ("nested_scopes", "generators", "division", "with_statement") def __init__(self): self.found = {} # set Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Thu Mar 2 02:56:53 2006 @@ -10,7 +10,8 @@ from pypy.interpreter.astcompiler.consts import SC_LOCAL, SC_GLOBAL, \ SC_FREE, SC_CELL, SC_DEFAULT, OP_APPLY, OP_ASSIGN, OP_DELETE, OP_NONE from pypy.interpreter.astcompiler.consts import CO_VARARGS, CO_VARKEYWORDS, \ - CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION + CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, \ + CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT from pypy.interpreter.pyparser.error import SyntaxError # drop VERSION dependency since it the ast transformer for 2.4 doesn't work with 2.3 anyway @@ -164,6 +165,8 @@ self._div_op = "BINARY_TRUE_DIVIDE" elif feature == "generators": self.graph.setFlag(CO_GENERATOR_ALLOWED) + elif feature == "with_statement": + self.graph.setFlag(CO_FUTURE_WITH_STATEMENT) def emit(self, inst ): return self.graph.emit( inst ) Modified: pypy/dist/pypy/interpreter/pycompiler.py ============================================================================== --- pypy/dist/pypy/interpreter/pycompiler.py (original) +++ pypy/dist/pypy/interpreter/pycompiler.py Thu Mar 2 02:56:53 2006 @@ -78,7 +78,7 @@ # faked compiler import warnings -import __future__ +from pypy.tool import __future__ compiler_flags = 0 compiler_features = {} for fname in __future__.all_feature_names: Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/astbuilder.py (original) +++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py Thu Mar 2 02:56:53 2006 @@ -10,7 +10,9 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.interpreter.pyparser.parsestring import parsestr -sym = pythonparse.PYTHON_PARSER.symbols +sym = pythonparse.PYTHON_PARSER.symbols +sym_with = pythonparse.PYTHON_PARSER.with_grammar.symbols + DEBUG_MODE = 0 ### Parsing utilites ################################################# @@ -520,7 +522,7 @@ ## where Var and Expr are AST subtrees and Token is a not yet ## reduced token ## -## AST_RULES is kept as a dictionnary to be rpython compliant this is the +## ASTRULES is kept as a dictionnary to be rpython compliant this is the ## main reason why build_* functions are not methods of the AstBuilder class ## @@ -1343,6 +1345,12 @@ names.append((name, as_name)) if index < l: # case ',' index += 1 + if from_name == '__future__': + for name, asname in names: + if name == 'with_statement': + # found from __future__ import with_statement + if not builder.with_enabled: + raise pythonparse.AlternateGrammarException() builder.push(ast.From(from_name, names, atoms[0].lineno)) @@ -1465,62 +1473,69 @@ else_ = atoms[index+2] # skip ':' builder.push(ast.TryExcept(body, handlers, else_, atoms[0].lineno)) - -ASTRULES = { - sym['atom'] : build_atom, - sym['power'] : build_power, - sym['factor'] : build_factor, - sym['term'] : build_term, - sym['arith_expr'] : build_arith_expr, - sym['shift_expr'] : build_shift_expr, - sym['and_expr'] : build_and_expr, - sym['xor_expr'] : build_xor_expr, - sym['expr'] : build_expr, - sym['comparison'] : build_comparison, - sym['comp_op'] : build_comp_op, - sym['or_test'] : build_or_test, - sym['and_test'] : build_and_test, - sym['not_test'] : build_not_test, - sym['test'] : build_test, - sym['testlist'] : build_testlist, - sym['expr_stmt'] : build_expr_stmt, - sym['small_stmt'] : return_one, - sym['simple_stmt'] : build_simple_stmt, - sym['single_input'] : build_single_input, - sym['file_input'] : build_file_input, - sym['testlist_gexp'] : build_testlist_gexp, - sym['lambdef'] : build_lambdef, - sym['old_lambdef'] : build_lambdef, - sym['trailer'] : build_trailer, - sym['arglist'] : build_arglist, - sym['subscript'] : build_subscript, - sym['listmaker'] : build_listmaker, - sym['funcdef'] : build_funcdef, - sym['classdef'] : build_classdef, - sym['return_stmt'] : build_return_stmt, - sym['suite'] : build_suite, - sym['if_stmt'] : build_if_stmt, - sym['pass_stmt'] : build_pass_stmt, - sym['break_stmt'] : build_break_stmt, - sym['for_stmt'] : build_for_stmt, - sym['while_stmt'] : build_while_stmt, - sym['with_stmt'] : build_with_stmt, - sym['import_name'] : build_import_name, - sym['import_from'] : build_import_from, - sym['yield_stmt'] : build_yield_stmt, - sym['continue_stmt'] : build_continue_stmt, - sym['del_stmt'] : build_del_stmt, - sym['assert_stmt'] : build_assert_stmt, - sym['exec_stmt'] : build_exec_stmt, - sym['print_stmt'] : build_print_stmt, - sym['global_stmt'] : build_global_stmt, - sym['raise_stmt'] : build_raise_stmt, - sym['try_stmt'] : build_try_stmt, - sym['exprlist'] : build_exprlist, - sym['decorator'] : build_decorator, - sym['eval_input'] : build_eval_input, +ASTRULES_Template = { + 'atom' : build_atom, + 'power' : build_power, + 'factor' : build_factor, + 'term' : build_term, + 'arith_expr' : build_arith_expr, + 'shift_expr' : build_shift_expr, + 'and_expr' : build_and_expr, + 'xor_expr' : build_xor_expr, + 'expr' : build_expr, + 'comparison' : build_comparison, + 'comp_op' : build_comp_op, + 'or_test' : build_or_test, + 'and_test' : build_and_test, + 'not_test' : build_not_test, + 'test' : build_test, + 'testlist' : build_testlist, + 'expr_stmt' : build_expr_stmt, + 'small_stmt' : return_one, + 'simple_stmt' : build_simple_stmt, + 'single_input' : build_single_input, + 'file_input' : build_file_input, + 'testlist_gexp' : build_testlist_gexp, + 'lambdef' : build_lambdef, + 'old_lambdef' : build_lambdef, + 'trailer' : build_trailer, + 'arglist' : build_arglist, + 'subscript' : build_subscript, + 'listmaker' : build_listmaker, + 'funcdef' : build_funcdef, + 'classdef' : build_classdef, + 'return_stmt' : build_return_stmt, + 'suite' : build_suite, + 'if_stmt' : build_if_stmt, + 'pass_stmt' : build_pass_stmt, + 'break_stmt' : build_break_stmt, + 'for_stmt' : build_for_stmt, + 'while_stmt' : build_while_stmt, + 'import_name' : build_import_name, + 'import_from' : build_import_from, + 'yield_stmt' : build_yield_stmt, + 'continue_stmt' : build_continue_stmt, + 'del_stmt' : build_del_stmt, + 'assert_stmt' : build_assert_stmt, + 'exec_stmt' : build_exec_stmt, + 'print_stmt' : build_print_stmt, + 'global_stmt' : build_global_stmt, + 'raise_stmt' : build_raise_stmt, + 'try_stmt' : build_try_stmt, + 'exprlist' : build_exprlist, + 'decorator' : build_decorator, + 'eval_input' : build_eval_input, } +# Build two almost identical ASTRULES dictionaries +ASTRULES = dict([(sym[key], value) for (key, value) in + ASTRULES_Template.iteritems()]) + +ASTRULES_Template['with_stmt'] = build_with_stmt +ASTRULES_with = dict([(sym_with[key], value) for (key, value) in + (ASTRULES_Template).iteritems()]) +del ASTRULES_Template + ## Stack elements definitions ################################### class BaseRuleObject(ast.Node): @@ -1657,6 +1672,12 @@ self.rule_stack = [] self.space = space self.source_encoding = None + self.ASTRULES = ASTRULES + self.with_enabled = False + + def enable_with(self): + self.ASTRULES = ASTRULES_with + self.with_enabled = True def context(self): return AstBuilderContext(self.rule_stack) @@ -1696,7 +1717,7 @@ if rule.is_root(): ## if DEBUG_MODE: ## print "ALT:", sym.sym_name[rule.codename], self.rule_stack - builder_func = ASTRULES.get(rule.codename, None) + builder_func = self.ASTRULES.get(rule.codename, None) if builder_func: builder_func(self, 1) else: @@ -1717,7 +1738,7 @@ if rule.is_root(): ## if DEBUG_MODE: ## print "SEQ:", sym.sym_name[rule.codename] - builder_func = ASTRULES.get(rule.codename, None) + builder_func = self.ASTRULES.get(rule.codename, None) if builder_func: # print "REDUCING SEQUENCE %s" % sym.sym_name[rule.codename] builder_func(self, elts_number) Modified: pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a (original) +++ pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a Thu Mar 2 02:56:53 2006 @@ -63,13 +63,12 @@ exec_stmt: 'exec' expr ['in' test [',' test]] assert_stmt: 'assert' test [',' test] -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite] for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite) -with_stmt: 'with' test [ NAME expr ] ':' suite # NB compile.c makes sure that the default except clause is last except_clause: 'except' [test [',' test]] suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT Added: pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a_with ============================================================================== --- (empty file) +++ pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a_with Thu Mar 2 02:56:53 2006 @@ -0,0 +1,130 @@ +# Grammar for Python + +# Note: Changing the grammar specified in this file will most likely +# require corresponding changes in the parser module +# (../Modules/parsermodule.c). If you can't make the changes to +# that module yourself, please co-ordinate the required changes +# with someone who can; ask around on python-dev for help. Fred +# Drake will probably be listening there. + +# Commands for Kees Blom's railroad program +#diagram:token NAME +#diagram:token NUMBER +#diagram:token STRING +#diagram:token NEWLINE +#diagram:token ENDMARKER +#diagram:token INDENT +#diagram:output\input python.bla +#diagram:token DEDENT +#diagram:output\textwidth 20.04cm\oddsidemargin 0.0cm\evensidemargin 0.0cm +#diagram:rules + +# Start symbols for the grammar: +# single_input is a single interactive statement; +# file_input is a module or sequence of commands read from an input file; +# eval_input is the input for the eval() and input() functions. +# NB: compound_stmt in single_input is followed by extra NEWLINE! +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +file_input: (NEWLINE | stmt)* ENDMARKER +eval_input: testlist NEWLINE* ENDMARKER + +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE +decorators: decorator+ +funcdef: [decorators] 'def' NAME parameters ':' suite +parameters: '(' [varargslist] ')' +varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] +fpdef: NAME | '(' fplist ')' +fplist: fpdef (',' fpdef)* [','] + +stmt: simple_stmt | compound_stmt +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE +small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt +expr_stmt: testlist (augassign testlist | ('=' testlist)*) +augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' +# For normal assignments, additional restrictions enforced by the interpreter +print_stmt: 'print' ( '>>' test [ (',' test)+ [','] ] | [ test (',' test)* [','] ] ) +del_stmt: 'del' exprlist +pass_stmt: 'pass' +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +break_stmt: 'break' +continue_stmt: 'continue' +return_stmt: 'return' [testlist] +yield_stmt: 'yield' testlist +raise_stmt: 'raise' [test [',' test [',' test]]] +import_stmt: import_name | import_from +import_name: 'import' dotted_as_names +import_from: 'from' dotted_name 'import' ('*' | '(' import_as_names [','] ')' | import_as_names) +import_as_name: NAME [NAME NAME] +dotted_as_name: dotted_name [NAME NAME] +import_as_names: import_as_name (',' import_as_name)* +dotted_as_names: dotted_as_name (',' dotted_as_name)* +dotted_name: NAME ('.' NAME)* +global_stmt: 'global' NAME (',' NAME)* +exec_stmt: 'exec' expr ['in' test [',' test]] +assert_stmt: 'assert' test [',' test] + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +while_stmt: 'while' test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] +try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break + ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite) +with_stmt: 'with' test [ NAME expr ] ':' suite +# NB compile.c makes sure that the default except clause is last +except_clause: 'except' [test [',' test]] +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT + +# Backward compatibility cruft to support: +# [ x for x in lambda: True, lambda: False if x() ] +# even while also allowing: +# lambda x: 5 if x else 2 +# (But not a mix of the two) +testlist_safe: old_test [(',' old_test)+ [',']] +old_test: or_test | old_lambdef +old_lambdef: 'lambda' [varargslist] ':' old_test + +test: or_test ['if' or_test 'else' test] | lambdef +or_test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is' 'not'|'is' +expr: xor_expr ('|' xor_expr)* +xor_expr: and_expr ('^' and_expr)* +and_expr: shift_expr ('&' shift_expr)* +shift_expr: arith_expr (('<<'|'>>') arith_expr)* +arith_expr: term (('+'|'-') term)* +term: factor (('*'|'/'|'%'|'//') factor)* +factor: ('+'|'-'|'~') factor | power +power: atom trailer* ['**' factor] +atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+ +listmaker: test ( list_for | (',' test)* [','] ) +testlist_gexp: test ( gen_for | (',' test)* [','] ) +lambdef: 'lambda' [varargslist] ':' test +# trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME +trailer: '(' ')' | '(' arglist ')' | '[' subscriptlist ']' | '.' NAME +subscriptlist: subscript (',' subscript)* [','] +subscript: '.' '.' '.' | [test] ':' [test] [sliceop] | test +sliceop: ':' [test] +exprlist: expr (',' expr)* [','] +testlist: test (',' test)* [','] +dictmaker: test ':' test (',' test ':' test)* [','] + +classdef: 'class' NAME ['(' testlist ')'] ':' suite + +# arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) +arglist: (argument ',')* ( '*' test [',' '**' test] | '**' test | argument | [argument ','] ) +argument: [test '='] test [gen_for] # Really [keyword '='] test + +list_iter: list_for | list_if +list_for: 'for' exprlist 'in' testlist_safe [list_iter] +list_if: 'if' test [list_iter] + +gen_iter: gen_for | gen_if +gen_for: 'for' exprlist 'in' or_test [gen_iter] +gen_if: 'if' test [gen_iter] + +testlist1: test (',' test)* + +# not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/pythonparse.py (original) +++ pypy/dist/pypy/interpreter/pyparser/pythonparse.py Thu Mar 2 02:56:53 2006 @@ -10,6 +10,7 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool.option import Options from pythonlexer import Source, match_encoding_declaration +from pypy.interpreter.astcompiler.consts import CO_FUTURE_WITH_STATEMENT import pysymbol import ebnfparse import sys @@ -18,6 +19,9 @@ from codeop import PyCF_DONT_IMPLY_DEDENT +class AlternateGrammarException(Exception): + pass + class PythonParser(object): """Wrapper class for python grammar""" def __init__(self, grammar_builder): @@ -26,6 +30,7 @@ # Build first sets for each rule (including anonymous ones) grammar.build_first_sets(self.items) self.symbols = grammar_builder.symbols + self.with_grammar = None def parse_source(self, textsrc, goal, builder, flags=0): """Parse a python source according to goal""" @@ -45,12 +50,22 @@ flags &= ~PyCF_DONT_IMPLY_DEDENT return self.parse_lines(lines, goal, builder, flags) + def parse_lines(self, lines, goal, builder, flags=0): + if (self.with_grammar is not None and # don't recurse into ourself + flags & CO_FUTURE_WITH_STATEMENT): + builder.enable_with() + return self.with_grammar.parse_lines(lines, goal, builder, flags) goalnumber = self.symbols.sym_values[goal] target = self.rules[goalnumber] src = Source(lines, flags) - result = target.match(src, builder) + try: + result = target.match(src, builder) + except AlternateGrammarException: # handle from __future__ import with_statement + if self.with_grammar is not None: + builder.enable_with() + return self.with_grammar.parse_lines(lines, goal, builder, flags) if not result: line, lineno = src.debug() # XXX needs better error messages @@ -133,6 +148,7 @@ debug_print( "Loading grammar %s" % PYTHON_GRAMMAR ) PYTHON_PARSER = python_grammar( PYTHON_GRAMMAR ) +PYTHON_PARSER.with_grammar = python_grammar( PYTHON_GRAMMAR + '_with' ) def reload_grammar(version): """helper function to test with pypy different grammars""" Modified: pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py (original) +++ pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py Thu Mar 2 02:56:53 2006 @@ -1,4 +1,5 @@ -# EXPECT: Module(None, Stmt([With(Name('acontext'), Stmt([Pass()]), None)])) +# EXPECT: Module(None, Stmt([From('__future__', [('with_statement', None)]), With(Name('acontext'), Stmt([Pass()]), None)])) +from __future__ import with_statement with acontext: pass Modified: pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py (original) +++ pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py Thu Mar 2 02:56:53 2006 @@ -1,4 +1,5 @@ -# EXPECT: Module(None, Stmt([With(Name('acontext'), Stmt([Pass()]), AssName('avariable', OP_ASSIGN))])) +# EXPECT: Module(None, Stmt([From('__future__', [('with_statement', None)]), With(Name('acontext'), Stmt([Pass()]), AssName('avariable', OP_ASSIGN))])) +from __future__ import with_statement with acontext as avariable: pass Modified: pypy/dist/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_syntax.py (original) +++ pypy/dist/pypy/interpreter/test/test_syntax.py Thu Mar 2 02:56:53 2006 @@ -259,8 +259,8 @@ class AppTestWith: def test_with_1(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -293,8 +293,8 @@ def test_with_2(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -329,8 +329,8 @@ def test_with_3(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -374,8 +374,8 @@ def test_with_4(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -415,8 +415,8 @@ def test_with_5(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -456,8 +456,8 @@ def test_with_6(self): - s = """if 1: - # from __future__ import with_statement + s = """from __future__ import with_statement +if 1: class ContextFactory: class Context: @@ -494,6 +494,25 @@ assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __return__'.split() assert acontextfact.exit_params == (None, None, None) + def test_with_7(self): + exec "with = 9" + + def test_with_8(self): + try: + exec "from __future__ import with_statement\nwith = 9" + except SyntaxError: + pass + else: + assert False, 'Assignment to with did not raise SyntaxError' + + def test_with_9(self): + s = """from __future__ import with_statement +if 1: + compile('''with x: + pass''', '', 'exec') + """ + exec s + if __name__ == '__main__': # only to check on top of CPython (you need 2.4) from py.test import raises Added: pypy/dist/pypy/tool/__future__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/tool/__future__.py Thu Mar 2 02:56:53 2006 @@ -0,0 +1,11 @@ +# load __future__.py constants + +def load_module(): + import py + module_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/__future__.py') + execfile(str(module_path), globals()) + +load_module() +del load_module + +# this could be generalized, it's also in opcode.py From auc at codespeak.net Thu Mar 2 14:08:27 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 2 Mar 2006 14:08:27 +0100 (CET) Subject: [pypy-svn] r23905 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060302130827.B94A9100A6@code0.codespeak.net> Author: auc Date: Thu Mar 2 14:08:25 2006 New Revision: 23905 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py pypy/dist/pypy/lib/logic/computation_space/test_variable.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: introduce spaceless variables use them for space impl. purposes Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Thu Mar 2 14:08:25 2006 @@ -11,8 +11,9 @@ from state import Succeeded, Distributable, Failed, \ Unknown, Forsaken -from variable import EqSet, Var, NoValue, NoDom, \ - VariableException, NotAVariable, AlreadyInStore +from variable import EqSet, CsVar, NoValue, NoDom, \ + VariableException, NotAVariable, AlreadyInStore, \ + AlreadyBound, SimpleVar from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor @@ -144,8 +145,8 @@ self.distributor = None self.parent = None self.children = None - self.CHOOSE.bind(0) - self.STABLE.bind(0) + self.CHOOSE.bind(True) + self.STABLE.bind(True) def __eq__(self, spc): """space equality defined as : @@ -196,15 +197,12 @@ #-- space helpers ----------------------------------------- def _make_choice_var(self): - ComputationSpace._nb_choices += 1 - ch_var = self.var('__choice__'+str(self._nb_choices)) - return ch_var + return SimpleVar() def _make_stable_var(self): - ComputationSpace._nb_choices += 1 - st_var = self.var('__stable__'+str(self._nb_choices)) - return st_var + return SimpleVar() + def _process(self): """wraps the propagator""" if len(self.event_set): @@ -268,10 +266,8 @@ """ # did you ask before ... ? assert self.STABLE.is_bound() - old_stable_var = self.STABLE self.STABLE = self._make_stable_var() - self._del_var(old_stable_var) - self.bind(self.CHOOSE, choice) + self.CHOOSE.bind(choice) def choose(self, nb_choices): """ @@ -293,7 +289,7 @@ #for var in self.root.val: # var.bind(self.dom(var).get_values()[0]) # shut down the distributor - self.CHOOSE.bind(0) + self.CHOOSE.bind(True) res = [] for var in self.root.val: res.append(self.dom(var).get_values()[0]) @@ -311,7 +307,7 @@ and puts it into the store""" self.var_lock.acquire() try: - v = Var(name, self) + v = CsVar(name, self) self.add_unbound(v) return v finally: @@ -372,14 +368,14 @@ def set_dom(self, var, dom): """bind variable to domain""" - assert(isinstance(var, Var) and (var in self.vars)) + assert(isinstance(var, CsVar) and (var in self.vars)) if var.is_bound(): print "warning : setting domain %s to bound var %s" \ % (dom, var) self.doms[var] = FiniteDomain(dom) def dom(self, var): - assert isinstance(var, Var) + assert isinstance(var, CsVar) try: return self.doms[var] except KeyError: @@ -596,7 +592,7 @@ # removed (this last condition remains to be checked) self.bind_lock.acquire() try: - assert(isinstance(var, Var) and (var in self.vars)) + assert(isinstance(var, CsVar) and (var in self.vars)) if var == val: return if _both_are_vars(var, val): @@ -745,7 +741,7 @@ return False if _mapping(term1) and _mapping(term2): return _mapping_unifiable(term1, term2) - if not(isinstance(term1, Var) or isinstance(term2, Var)): + if not(isinstance(term1, CsVar) or isinstance(term2, CsVar)): return term1 == term2 # same 'atomic' object return True @@ -774,7 +770,7 @@ #-- Some utilities ------------------------------------------- def _both_are_vars(v1, v2): - return isinstance(v1, Var) and isinstance(v2, Var) + return isinstance(v1, CsVar) and isinstance(v2, CsVar) def _both_are_bound(v1, v2): return v1._is_bound() and v2._is_bound() Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Thu Mar 2 14:08:25 2006 @@ -153,12 +153,9 @@ print "-- distribution & propagation (%s) --" % self.cs.id self.distribute(choice-1) self.cs._process() - old_choose_var = self.cs.CHOOSE self.cs.CHOOSE = self.cs._make_choice_var() - self.cs._del_var(old_choose_var) self.cs.STABLE.bind(True) # unlocks Ask print "-- distributor terminated (%s) --" % self.cs.id - self.cs.STABLE.bind(True) # it can't hurt ... def distribute(self, choice): Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Thu Mar 2 14:08:25 2006 @@ -41,7 +41,34 @@ #-- meat ---------------------------- -class TestVariable: +class TestSimpleVariable: + + def test_basics(self): + x = v.SimpleVar() + assert x.val == v.NoValue + x.bind(42) + assert x.val == 42 + x.bind(42) + raises(v.AlreadyBound, x.bind, 43) + + def test_dataflow(self): + def fun(thread, var): + thread.state = 1 + v = var.get() + thread.state = v + + x = v.SimpleVar() + t = FunThread(fun, x) + import time + t.start() + time.sleep(.5) + assert t.state == 1 + x.bind(42) + t.join() + assert t.state == 42 + + +class TestCsVariable: def test_no_same_name(self): sp = newspace() Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Thu Mar 2 14:08:25 2006 @@ -9,9 +9,15 @@ def __str__(self): return "%s already in store" % self.name -class AlreadyBound(VariableException): +class AlreadyBound(Exception): + def __init__(self, var, val): + self.var = var + self.val = val + def __str__(self): - return "%s is already bound" % self.name + return "%s:%s already bound to %s" % (self.var.name, + self.var.val, + self.val) class NotAVariable(VariableException): def __str__(self): @@ -25,16 +31,25 @@ class NoDom: pass class SimpleVar(object): - def __init__(self, name): - self.name = name + """Spaceless dataflow variable""" + + def __init__(self): + self.name = str(id(self)) self._val = NoValue # a condition variable for concurrent access self._value_condition = threading.Condition() # value accessors def _set_val(self, val): - if val != NoValue: - raise AlreadyBound(self.name) + self._value_condition.acquire() + try: + if self._val != NoValue: + if val != self._val: + raise AlreadyBound(self, val) + self._val = val + self._value_condition.notifyAll() + finally: + self._value_condition.release() def _get_val(self): return self._val @@ -60,14 +75,14 @@ """ try: self._value_condition.acquire() - while not self._is_bound(): + while not self.is_bound(): self._value_condition.wait() return self.val finally: self._value_condition.release() -class Var(SimpleVar): +class CsVar(SimpleVar): """Dataflow variable linked to a space""" def __init__(self, name, cs): @@ -103,13 +118,15 @@ # value accessors def _set_val(self, val): self._value_condition.acquire() - if self._cs.in_transaction: - if not self._changed: - self._previous = self._val - self._changed = True - self._val = val - self._value_condition.notifyAll() - self._value_condition.release() + try: + if self._cs.in_transaction: + if not self._changed: + self._previous = self._val + self._changed = True + self._val = val + self._value_condition.notifyAll() + finally: + self._value_condition.release() def _get_val(self): return self._val @@ -124,7 +141,7 @@ return self.__str__() def __eq__(self, thing): - return isinstance(thing, Var) \ + return isinstance(thing, self.__class__) \ and self.name == thing.name def bind(self, val): From auc at codespeak.net Thu Mar 2 14:21:37 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 2 Mar 2006 14:21:37 +0100 (CET) Subject: [pypy-svn] r23907 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060302132137.C7CA9100A7@code0.codespeak.net> Author: auc Date: Thu Mar 2 14:21:30 2006 New Revision: 23907 Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py Log: stream test for simple vars Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Thu Mar 2 14:21:30 2006 @@ -67,6 +67,24 @@ t.join() assert t.state == 42 + def test_stream(self): + def consummer(thread, S): + v = S.get() + if v: + thread.res += v[0] + consummer(thread, v[1]) + + S = v.SimpleVar() + t = FunThread(consummer, S) + t.res = 0 + t.start() + for i in range(10): + tail = v.SimpleVar() + S.bind((i, tail)) + S = tail + S.bind(None) + t.join() + assert t.res == 45 class TestCsVariable: From arigo at codespeak.net Thu Mar 2 17:01:26 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Mar 2006 17:01:26 +0100 (CET) Subject: [pypy-svn] r23913 - pypy/dist/pypy/translator/tool Message-ID: <20060302160126.AD32B100B2@code0.codespeak.net> Author: arigo Date: Thu Mar 2 17:01:17 2006 New Revision: 23913 Modified: pypy/dist/pypy/translator/tool/graphpage.py Log: Gray out Void variables. Modified: pypy/dist/pypy/translator/tool/graphpage.py ============================================================================== --- pypy/dist/pypy/translator/tool/graphpage.py (original) +++ pypy/dist/pypy/translator/tool/graphpage.py Thu Mar 2 17:01:17 2006 @@ -169,6 +169,8 @@ #info = self.links.get(var.name, var.name) #info = '(%s) %s' % (var.concretetype, info) info = str(var.concretetype) + if info == 'Void': # gray out Void variables + info = info, (160,160,160) self.links[var.name] = info for graph in graphs: From arigo at codespeak.net Thu Mar 2 17:03:18 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Mar 2006 17:03:18 +0100 (CET) Subject: [pypy-svn] r23915 - in pypy/dist/pypy: rpython rpython/test translator/c translator/c/test Message-ID: <20060302160318.BEBAA100BC@code0.codespeak.net> Author: arigo Date: Thu Mar 2 17:03:09 2006 New Revision: 23915 Modified: pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/test/test_llinterp.py pypy/dist/pypy/translator/c/funcgen.py pypy/dist/pypy/translator/c/test/test_boehm.py pypy/dist/pypy/translator/c/test/test_genc.py Log: Added/fixed support for SpaceOperation.cleanup in the llinterpreter and in genc. Added painfully-written tests. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Thu Mar 2 17:03:09 2006 @@ -256,9 +256,25 @@ # if these special cases pile up, do something better here if operation.opname in ['cast_pointer', 'ooupcast', 'oodowncast', 'cast_adr_to_ptr']: vals.insert(0, operation.result.concretetype) - retval = ophandler(*vals) + try: + retval = ophandler(*vals) + except LLException: + self.handle_cleanup(operation, exception=True) + raise + else: + self.handle_cleanup(operation) self.setvar(operation.result, retval) + def handle_cleanup(self, operation, exception=False): + cleanup = getattr(operation, 'cleanup', None) + if cleanup is not None: + cleanup_finally, cleanup_except = cleanup + for op in cleanup_finally: + self.eval_operation(op) + if exception: + for op in cleanup_except: + self.eval_operation(op) + def make_llexception(self, exc=None): if exc is None: original = sys.exc_info() Modified: pypy/dist/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_llinterp.py (original) +++ pypy/dist/pypy/rpython/test/test_llinterp.py Thu Mar 2 17:03:09 2006 @@ -423,6 +423,58 @@ fgraph.startblock.operations[0].opname = "flavored_malloc" fgraph.startblock.operations[0].args.insert(0, inputconst(Void, "stack")) py.test.raises(AttributeError, "interp.eval_graph(graph, [])") + + +def test_cleanup_finally(): + interp, graph = get_interpreter(cleanup_f, [-1]) + _tcache.clear() # because we hack the graph in place + operations = graph.startblock.operations + assert operations[0].opname == "direct_call" + assert operations[1].opname == "direct_call" + assert getattr(operations[0], 'cleanup', None) is None + assert getattr(operations[1], 'cleanup', None) is None + cleanup_finally = (operations.pop(1),) + cleanup_except = () + operations[0].cleanup = cleanup_finally, cleanup_except + + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 102 + # state.current == 2 + res = interp.eval_graph(graph, [1]) + assert res == 203 + # state.current == 3 + py.test.raises(LLException, "interp.eval_graph(graph, [-1])") + # state.current == 4 + res = interp.eval_graph(graph, [1]) + assert res == 405 + # state.current == 5 + +def test_cleanup_except(): + interp, graph = get_interpreter(cleanup_f, [-1]) + _tcache.clear() # because we hack the graph in place + operations = graph.startblock.operations + assert operations[0].opname == "direct_call" + assert operations[1].opname == "direct_call" + assert getattr(operations[0], 'cleanup', None) is None + assert getattr(operations[1], 'cleanup', None) is None + cleanup_finally = () + cleanup_except = (operations.pop(1),) + operations[0].cleanup = cleanup_finally, cleanup_except + + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 101 + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 101 + # state.current == 1 + py.test.raises(LLException, "interp.eval_graph(graph, [-1])") + # state.current == 2 + res = interp.eval_graph(graph, [1]) + assert res == 202 + # state.current == 2 + #__________________________________________________________________ # example functions for testing the LLInterpreter _snap = globals().copy() @@ -483,3 +535,19 @@ except ValueError: raise TypeError +# test for the 'cleanup' attribute of SpaceOperations +class CleanupState(object): + pass +cleanup_state = CleanupState() +cleanup_state.current = 1 +def cleanup_g(n): + cleanup_state.saved = cleanup_state.current + if n < 0: + raise ZeroDivisionError +def cleanup_h(): + cleanup_state.current += 1 +def cleanup_f(n): + cleanup_g(n) + cleanup_h() # the test hacks the graph to put this h() in the + # cleanup clause of the previous direct_call(g) + return cleanup_state.saved * 100 + cleanup_state.current Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Thu Mar 2 17:03:09 2006 @@ -52,10 +52,9 @@ for op in block.operations: mix.extend(op.args) mix.append(op.result) - if hasattr(op, "cleanup"): - if op.cleanup is None: - continue - for cleanupop in op.cleanup[0] + op.cleanup[1]: + if getattr(op, "cleanup", None) is not None: + cleanup_finally, cleanup_except = op.cleanup + for cleanupop in cleanup_finally + cleanup_except: mix.extend(cleanupop.args) mix.append(cleanupop.result) for link in block.exits: @@ -164,7 +163,7 @@ seen[name] = True result = cdecl(self.lltypename(v), LOCALVAR % name) + ';' if self.lltypemap(v) is Void: - result = '/*%s*/' % result + continue #result = '/*%s*/' % result result_by_name.append((v._name, result)) result_by_name.sort() return [result for name, result in result_by_name] @@ -184,9 +183,13 @@ err = 'err%d_%d' % (myblocknum, i) for line in self.gen_op(op, err): yield line + # XXX hackish -- insert the finally code unless the operation + # already did cleanup = getattr(op, 'cleanup', None) - if cleanup is not None: - for subop in op.cleanup[0]: + if (cleanup is not None and + op.opname not in ("direct_call", "indirect_call")): + cleanup_finally, cleanup_except = cleanup + for subop in cleanup_finally: for line in self.gen_op(subop, "should_never_be_jumped_to2"): yield line fallthrough = False @@ -308,10 +311,11 @@ for i, op in list(enumerate(block.operations))[::-1]: if getattr(op, 'cleanup', None) is None: continue - errorcases.setdefault(op.cleanup[1], []).append(i) + cleanup_finally, cleanup_except = op.cleanup + errorcases.setdefault(cleanup_except, []).append(i) if fallthrough: - firstclean = tuple(block.operations[-1].cleanup[1]) + cleanup_finally, firstclean = block.operations[-1].cleanup first = errorcases[firstclean] del errorcases[firstclean] first.remove(len(block.operations) - 1) @@ -423,6 +427,14 @@ except AttributeError: raise AttributeError("(in)direct_call %r without explicit .cleanup" % op) if cleanup is not None: + # insert the 'finally' operations before the exception check + cleanup_finally, cleanup_except = op.cleanup + if cleanup_finally: + finally_lines = ['/* finally: */'] + for cleanupop in cleanup_finally: + finally_lines.extend( + self.gen_op(cleanupop, 'should_never_be_jumped_to')) + line = '%s\n%s' % (line, '\n\t'.join(finally_lines)) line = '%s\n%s' % (line, self.check_directcall_result(op, err)) return line Modified: pypy/dist/pypy/translator/c/test/test_boehm.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_boehm.py (original) +++ pypy/dist/pypy/translator/c/test/test_boehm.py Thu Mar 2 17:03:09 2006 @@ -2,6 +2,7 @@ from pypy.translator.translator import TranslationContext from pypy.translator.tool.cbuild import skip_missing_compiler, check_boehm_presence from pypy.translator.c.genc import CExtModuleBuilder +from pypy import conftest def setup_module(mod): if not check_boehm_presence(): @@ -32,6 +33,8 @@ def compile(): cbuilder = CExtModuleBuilder(t, func, gcpolicy=self.gcpolicy) c_source_filename = cbuilder.generate_source() + if conftest.option.view: + t.view() cbuilder.compile() mod = cbuilder.isolated_import() self._cleanups.append(cbuilder.cleanup) # schedule cleanup after test Modified: pypy/dist/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_genc.py (original) +++ pypy/dist/pypy/translator/c/test/test_genc.py Thu Mar 2 17:03:09 2006 @@ -4,6 +4,7 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c.genc import gen_source +from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph from pypy.tool.udir import udir @@ -28,18 +29,19 @@ include_dirs = [os.path.dirname(autopath.this_dir)]) return m -def compile(fn, argtypes, view=False): +def compile(fn, argtypes, view=False, gcpolicy=None, backendopt=True): t = TranslationContext() a = t.buildannotator() a.build_types(fn, argtypes) t.buildrtyper().specialize() - if view or conftest.option.view: - t.view() - backend_optimizations(t) - db = LowLevelDatabase(t) + if backendopt: + backend_optimizations(t) + db = LowLevelDatabase(t, gcpolicy=gcpolicy) entrypoint = db.get(pyobjectptr(fn)) db.complete() module = compile_db(db) + if view or conftest.option.view: + t.view() compiled_fn = getattr(module, entrypoint) def checking_fn(*args, **kwds): res = compiled_fn(*args, **kwds) @@ -296,3 +298,91 @@ f1 = compile(f, []) assert f1() == 1 + +# ____________________________________________________________ +# test for the 'cleanup' attribute of SpaceOperations +class CleanupState(object): + pass +cleanup_state = CleanupState() +cleanup_state.current = 1 +def cleanup_g(n): + cleanup_state.saved = cleanup_state.current + try: + return 10 // n + except ZeroDivisionError: + raise +def cleanup_h(): + cleanup_state.current += 1 +def cleanup_f(n): + cleanup_g(n) + cleanup_h() # the test hacks the graph to put this h() in the + # cleanup clause of the previous direct_call(g) + return cleanup_state.saved * 100 + cleanup_state.current + +def test_cleanup_finally(): + class DummyGCTransformer(NoneGcPolicy.transformerclass): + def transform_graph(self, graph): + super(DummyGCTransformer, self).transform_graph(graph) + if graph is self.translator.graphs[0]: + operations = graph.startblock.operations + op_call_g = operations[0] + op_call_h = operations.pop(1) + assert op_call_g.opname == "direct_call" + assert op_call_h.opname == "direct_call" + assert op_call_g.cleanup == ((), ()) + assert op_call_h.cleanup == ((), ()) + cleanup_finally = (op_call_h,) + cleanup_except = () + op_call_g.cleanup = cleanup_finally, cleanup_except + op_call_h.cleanup = None + + class DummyGcPolicy(NoneGcPolicy): + transformerclass = DummyGCTransformer + + f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) + # state.current == 1 + res = f1(1) + assert res == 102 + # state.current == 2 + res = f1(1) + assert res == 203 + # state.current == 3 + py.test.raises(ZeroDivisionError, f1, 0) + # state.current == 4 + res = f1(1) + assert res == 405 + # state.current == 5 + +def test_cleanup_except(): + class DummyGCTransformer(NoneGcPolicy.transformerclass): + def transform_graph(self, graph): + super(DummyGCTransformer, self).transform_graph(graph) + if graph is self.translator.graphs[0]: + operations = graph.startblock.operations + op_call_g = operations[0] + op_call_h = operations.pop(1) + assert op_call_g.opname == "direct_call" + assert op_call_h.opname == "direct_call" + assert op_call_g.cleanup == ((), ()) + assert op_call_h.cleanup == ((), ()) + cleanup_finally = () + cleanup_except = (op_call_h,) + op_call_g.cleanup = cleanup_finally, cleanup_except + op_call_h.cleanup = None + + class DummyGcPolicy(NoneGcPolicy): + transformerclass = DummyGCTransformer + + f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) + # state.current == 1 + res = f1(1) + assert res == 101 + # state.current == 1 + res = f1(1) + assert res == 101 + # state.current == 1 + py.test.raises(ZeroDivisionError, f1, 0) + # state.current == 2 + res = f1(1) + assert res == 202 + # state.current == 2 From goden at codespeak.net Thu Mar 2 17:54:30 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Thu, 2 Mar 2006 17:54:30 +0100 (CET) Subject: [pypy-svn] r23916 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20060302165430.DC06D100BA@code0.codespeak.net> Author: goden Date: Thu Mar 2 17:54:26 2006 New Revision: 23916 Modified: pypy/dist/pypy/rpython/rctypes/rarray.py pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/dist/pypy/rpython/rctypes/test/test_rarray.py pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Log: (arigo, goden) - implemented the boxed form of CTypes primitive specialization with working construction and ".value" access. Modified: pypy/dist/pypy/rpython/rctypes/rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/rarray.py Thu Mar 2 17:54:26 2006 @@ -8,13 +8,6 @@ ArrayType = type(ARRAY(c_int, 10)) -def arraytype_compute_annotation(metatype, type): - def compute_result_annotation(*arg_s): - return SomeCTypesObject(type, SomeCTypesObject.OWNSMEMORY) - return SomeBuiltin(compute_result_annotation, - methodname=type.__name__) - - class ArrayRepr(Repr): def __init__(self, rtyper, type): @@ -60,6 +53,12 @@ ], resulttype=r_array.lowleveltype, ) +def arraytype_compute_annotation(metatype, type): + def compute_result_annotation(*arg_s): + return SomeCTypesObject(type, SomeCTypesObject.OWNSMEMORY) + return SomeBuiltin(compute_result_annotation, + methodname=type.__name__) + extregistry.register_type(ArrayType, compute_annotation=arraytype_compute_annotation, specialize_call=arraytype_specialize_call) Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/rprimitive.py Thu Mar 2 17:54:26 2006 @@ -24,23 +24,69 @@ (c_double, lltype.Float), ] +class PrimitiveRepr(Repr): + def __init__(self, rtyper, type, ll_type): + self.ll_type = ll_type + self.lowleveltype = lltype.Ptr( + lltype.GcStruct( "CtypesBox_%s" % (type.__name__,), + ( "c_data", lltype.Struct('C_Data_%s' % (type.__name__,), + ('value', ll_type) ) + ) + ) + ) + + def rtype_getattr(self, hop): + s_attr = hop.args_s[1] + assert s_attr.is_constant() + assert s_attr.const == 'value' + v_primitive = hop.inputarg(self, 0) + cname = hop.inputconst(lltype.Void, 'value') + inputargs = [v_primitive, hop.inputconst(lltype.Void, "c_data")] + v_c_data = hop.genop('getsubstruct', + inputargs, + lltype.Ptr(self.lowleveltype.TO.c_data) ) + + return hop.genop('getfield', [v_c_data, cname], + resulttype=self.ll_type) + + +def primitive_specialize_call(hop): + r_primitive = hop.r_result + c1 = hop.inputconst(lltype.Void, r_primitive.lowleveltype.TO) + v_result = hop.genop("malloc", [c1], resulttype=r_primitive.lowleveltype) + inputargs = [v_result, hop.inputconst(lltype.Void, "c_data")] + v_c_data = hop.genop('getsubstruct', + inputargs, + lltype.Ptr(r_primitive.lowleveltype.TO.c_data) ) + cname = hop.inputconst(lltype.Void, 'value') + if len(hop.args_s): + v_value, = hop.inputargs(r_primitive.ll_type) + + hop.genop('setfield', [v_c_data, cname, v_value]) + return v_result + def do_register(the_type, ll_type): - def annotation_function(s_arg): + def compute_result_annotation_function(s_arg=None): return annmodel.SomeCTypesObject(the_type, annmodel.SomeCTypesObject.OWNSMEMORY) - extregistry.register_value(the_type, - compute_result_annotation=annotation_function) - entry = extregistry.register_type(the_type) + compute_result_annotation=compute_result_annotation_function, + specialize_call=primitive_specialize_call + ) + + def compute_prebuilt_instance_annotation(the_type, instance): + return annmodel.SomeCTypesObject(the_type, + annmodel.SomeCTypesObject.OWNSMEMORY) + + def primitive_get_repr(rtyper, s_primitive): + return PrimitiveRepr(rtyper, s_primitive.knowntype, ll_type) + + entry = extregistry.register_type(the_type, + compute_annotation=compute_prebuilt_instance_annotation, + get_repr=primitive_get_repr, + ) entry.fields_s = {'value': annmodel.lltype_to_annotation(ll_type)} + entry.lowleveltype = ll_type for the_type, ll_type in ctypes_annotation_list: do_register(the_type, ll_type) - -#extregistry.register_type(ArrayType, -# compute_annotation=arraytype_compute_annotation, -# specialize_call=arraytype_specialize_call) - -#def arraytype_get_repr(rtyper, s_array): -# return ArrayRepr(rtyper, s_array.knowntype) -#extregistry.register_metatype(ArrayType, get_repr=arraytype_get_repr) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Thu Mar 2 17:54:26 2006 @@ -8,7 +8,6 @@ from pypy import conftest import sys from pypy.rpython.test.test_llinterp import interpret -from pypy.rpython.rctypes.test.test_rctypes import compile try: import ctypes @@ -20,7 +19,9 @@ c_int_10 = ARRAY(c_int,10) c_int_p_test = POINTER(c_int) -class Test_array: +py.test.skip("Reworking primitive types") + +class Test_annotation: def test_annotate_array(self): def create_array(): return c_int_10() @@ -125,9 +126,10 @@ py.test.raises(IndexError, "s = a.build_types(access_with_invalid_negative_index,[])") +class Test_specialization: def test_specialize_array(self): def create_array(): - return c_int_10() + return c_int_10() res = interpret(create_array, []) c_data = res.c_data Modified: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Thu Mar 2 17:54:26 2006 @@ -34,3 +34,46 @@ if conftest.option.view: t.view() + + def test_annotate_c_int_2(self): + res = c_int(42) + + def func(): + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == int + + if conftest.option.view: + t.view() + +class Test_specialization: + def test_specialize_c_int(self): + def create_c_int(): + return c_int(42) + res = interpret(create_c_int, []) + c_data = res.c_data + assert c_data.value == 42 + + def test_specialize_c_int_default_value(self): + def create_c_int(): + return c_int() + res = interpret(create_c_int, []) + c_data = res.c_data + assert c_data.value == 0 + + def test_specialize_c_int_access_value(self): + def create_c_int(): + return c_int(42).value + res = interpret(create_c_int, []) + assert res == 42 + +class Test_compilation: + def test_compile_c_int(self): + def create_c_int(): + return c_int(42).value + fn = compile(create_c_int, []) + assert fn() == 42 From nik at codespeak.net Thu Mar 2 18:09:55 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 18:09:55 +0100 (CET) Subject: [pypy-svn] r23917 - pypy/dist/pypy/rpython/test Message-ID: <20060302170955.39071100B6@code0.codespeak.net> Author: nik Date: Thu Mar 2 18:09:42 2006 New Revision: 23917 Modified: pypy/dist/pypy/rpython/test/test_rclass.py Log: (nik, pedronis around) run test_rclass tests on both lltypesystem and ootypesystem. all tests pass on ootype except __del__ tests, which need some thought. Modified: pypy/dist/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rclass.py (original) +++ pypy/dist/pypy/rpython/test/test_rclass.py Thu Mar 2 18:09:42 2006 @@ -1,79 +1,18 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.lltypesystem.lltype import * +from pypy.rpython.ootypesystem import ootype from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.rarithmetic import intmask + class EmptyBase(object): pass - -def test_simple(): - def dummyfn(): - x = EmptyBase() - return x - res = interpret(dummyfn, []) - T = typeOf(res) - assert isinstance(T, Ptr) and isinstance(T.TO, GcStruct) - -def test_instanceattr(): - def dummyfn(): - x = EmptyBase() - x.a = 5 - x.a += 1 - return x.a - res = interpret(dummyfn, []) - assert res == 6 - class Random: xyzzy = 12 yadda = 21 -def test_classattr(): - def dummyfn(): - x = Random() - return x.xyzzy - res = interpret(dummyfn, []) - assert res == 12 - -def test_classattr_as_defaults(): - def dummyfn(): - x = Random() - x.xyzzy += 1 - return x.xyzzy - res = interpret(dummyfn, []) - assert res == 13 - -def test_prebuilt_instance(): - a = EmptyBase() - a.x = 5 - def dummyfn(): - a.x += 1 - return a.x - interpret(dummyfn, []) - -def test_recursive_prebuilt_instance(): - a = EmptyBase() - b = EmptyBase() - a.x = 5 - b.x = 6 - a.peer = b - b.peer = a - def dummyfn(): - return a.peer.peer.peer.x - res = interpret(dummyfn, []) - assert res == 6 - -def test_prebuilt_instances_with_void(): - def marker(): - return 42 - a = EmptyBase() - a.nothing_special = marker - def dummyfn(): - return a.nothing_special() - res = interpret(dummyfn, []) - assert res == 42 - -# method calls +# for method calls class A: def f(self): return self.g() @@ -88,287 +27,355 @@ class C(B): pass -def test_simple_method_call(): - def f(i): - if i: - a = A() - else: - a = B() - return a.f() - res = interpret(f, [True]) - assert res == 42 - res = interpret(f, [False]) - assert res == 1 +class BaseTestRclass: -def test_isinstance(): - def f(i): - if i == 0: - o = None - elif i == 1: - o = A() - elif i == 2: - o = B() + def test_instanceattr(self): + def dummyfn(): + x = EmptyBase() + x.a = 5 + x.a += 1 + return x.a + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 6 + + def test_simple(self): + def dummyfn(): + x = EmptyBase() + return x + res = interpret(dummyfn, [], type_system=self.ts) + T = typeOf(res) + if self.ts == "lltype": + assert isinstance(T, Ptr) and isinstance(T.TO, GcStruct) else: - o = C() - return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C) + assert isinstance(T, ootype.Instance) - res = interpret(f, [1]) - assert res == 100 - res = interpret(f, [2]) - assert res == 110 - res = interpret(f, [3]) - assert res == 111 - - res = interpret(f, [0]) - assert res == 0 - -def test_method_used_in_subclasses_only(): - class A: - def meth(self): - return 123 - class B(A): - pass - def f(): - x = B() - return x.meth() - res = interpret(f, []) - assert res == 123 - -def test_method_both_A_and_B(): - class A: - def meth(self): - return 123 - class B(A): - pass - def f(): - a = A() - b = B() - return a.meth() + b.meth() - res = interpret(f, []) - assert res == 246 -def test_issubclass_type(): - class Abstract: - pass - class A(Abstract): - pass - class B(A): - pass - def f(i): - if i == 0: - c1 = A() - else: - c1 = B() - return issubclass(type(c1), B) - assert interpret(f, [0], view=False, viewbefore=False) == False - assert interpret(f, [1], view=False, viewbefore=False) == True - - def g(i): - if i == 0: - c1 = A() - else: - c1 = B() - return issubclass(type(c1), A) - assert interpret(g, [0], view=False, viewbefore=False) == True - assert interpret(g, [1], view=False, viewbefore=False) == True - -def test_staticmethod(): - class A(object): - f = staticmethod(lambda x, y: x*y) - def f(): - a = A() - return a.f(6, 7) - res = interpret(f, []) - assert res == 42 - -def test_is(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() - c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) | - 0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) | - 0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) | - 0x0200*(d is e)) - res = interpret(f, [0]) - assert res == 0x0004 - res = interpret(f, [1]) - assert res == 0x0020 - res = interpret(f, [2]) - assert res == 0x0100 - res = interpret(f, [3]) - assert res == 0x0200 - -def test_eq(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() - c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a == b) | 0x0002*(a == c) | 0x0004*(a == d) | - 0x0008*(a == e) | 0x0010*(b == c) | 0x0020*(b == d) | - 0x0040*(b == e) | 0x0080*(c == d) | 0x0100*(c == e) | - 0x0200*(d == e)) - res = interpret(f, [0]) - assert res == 0x0004 - res = interpret(f, [1]) - assert res == 0x0020 - res = interpret(f, [2]) - assert res == 0x0100 - res = interpret(f, [3]) - assert res == 0x0200 - -def test_istrue(): - class A: - pass - def f(i): - if i == 0: + def test_classattr(self): + def dummyfn(): + x = Random() + return x.xyzzy + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 12 + + def test_classattr_as_defaults(self): + def dummyfn(): + x = Random() + x.xyzzy += 1 + return x.xyzzy + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 13 + + def test_prebuilt_instance(self): + a = EmptyBase() + a.x = 5 + def dummyfn(): + a.x += 1 + return a.x + interpret(dummyfn, [], type_system=self.ts) + + def test_recursive_prebuilt_instance(self): + a = EmptyBase() + b = EmptyBase() + a.x = 5 + b.x = 6 + a.peer = b + b.peer = a + def dummyfn(): + return a.peer.peer.peer.x + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 6 + + def test_prebuilt_instances_with_void(self): + def marker(): + return 42 + a = EmptyBase() + a.nothing_special = marker + def dummyfn(): + return a.nothing_special() + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 42 + + def test_simple_method_call(self): + def f(i): + if i: + a = A() + else: + a = B() + return a.f() + res = interpret(f, [True], type_system=self.ts) + assert res == 42 + res = interpret(f, [False], type_system=self.ts) + assert res == 1 + + def test_isinstance(self): + def f(i): + if i == 0: + o = None + elif i == 1: + o = A() + elif i == 2: + o = B() + else: + o = C() + return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C) + + res = interpret(f, [1], type_system=self.ts) + assert res == 100 + res = interpret(f, [2], type_system=self.ts) + assert res == 110 + res = interpret(f, [3], type_system=self.ts) + assert res == 111 + + res = interpret(f, [0], type_system=self.ts) + assert res == 0 + + def test_method_used_in_subclasses_only(self): + class A: + def meth(self): + return 123 + class B(A): + pass + def f(): + x = B() + return x.meth() + res = interpret(f, [], type_system=self.ts) + assert res == 123 + + def test_method_both_A_and_B(self): + class A: + def meth(self): + return 123 + class B(A): + pass + def f(): a = A() - else: - a = None - if a: - return 1 - else: - return 2 - res = interpret(f, [0]) - assert res == 1 - res = interpret(f, [1]) - assert res == 2 - -def test_ne(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() - c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a != b) | 0x0002*(a != c) | 0x0004*(a != d) | - 0x0008*(a != e) | 0x0010*(b != c) | 0x0020*(b != d) | - 0x0040*(b != e) | 0x0080*(c != d) | 0x0100*(c != e) | - 0x0200*(d != e)) - res = interpret(f, [0]) - assert res == ~0x0004 & 0x3ff - res = interpret(f, [1]) - assert res == ~0x0020 & 0x3ff - res = interpret(f, [2]) - assert res == ~0x0100 & 0x3ff - res = interpret(f, [3]) - assert res == ~0x0200 & 0x3ff - -def test_hash_preservation(): - class C: - pass - class D(C): - pass - c = C() - d = D() - def f(): - d2 = D() - x = hash(d2) == id(d2) # xxx check for this CPython peculiarity for now - return x, hash(c)+hash(d) - - res = interpret(f, []) - - assert res.item0 == True - assert res.item1 == intmask(hash(c)+hash(d)) - -def test_type(): - class A: - pass - class B(A): - pass - def g(a): - return type(a) - def f(i): - if i > 0: + b = B() + return a.meth() + b.meth() + res = interpret(f, [], type_system=self.ts) + assert res == 246 + + def test_issubclass_type(self): + class Abstract: + pass + class A(Abstract): + pass + class B(A): + pass + def f(i): + if i == 0: + c1 = A() + else: + c1 = B() + return issubclass(type(c1), B) + assert interpret(f, [0], type_system=self.ts) == False + assert interpret(f, [1], type_system=self.ts) == True + + def g(i): + if i == 0: + c1 = A() + else: + c1 = B() + return issubclass(type(c1), A) + assert interpret(g, [0], type_system=self.ts) == True + assert interpret(g, [1], type_system=self.ts) == True + + def test_staticmethod(self): + class A(object): + f = staticmethod(lambda x, y: x*y) + def f(): a = A() - elif i < 0: - a = B() - else: - a = None - return g(a) is A # should type(None) work? returns None for now - res = interpret(f, [1]) - assert res is True - res = interpret(f, [-1]) - assert res is False - res = interpret(f, [0]) - assert res is False - -def test_void_fnptr(): - def g(): - return 42 - def f(): - e = EmptyBase() - e.attr = g - return e.attr() - res = interpret(f, []) - assert res == 42 - -def test_getattr_on_classes(): - class A: - def meth(self): - return self.value + 42 - class B(A): - def meth(self): - shouldnt**be**seen - class C(B): - def meth(self): - return self.value - 1 - def pick_class(i): - if i > 0: - return A - else: - return C - def f(i): - meth = pick_class(i).meth - x = C() - x.value = 12 - return meth(x) # calls A.meth or C.meth, completely ignores B.meth - res = interpret(f, [1]) - assert res == 54 - res = interpret(f, [0]) - assert res == 11 - -def test_constant_bound_method(): - class C: - value = 1 - def meth(self): - return self.value - meth = C().meth - def f(): - return meth() - res = interpret(f, []) - assert res == 1 + return a.f(6, 7) + res = interpret(f, [], type_system=self.ts) + assert res == 42 + + def test_is(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) | + 0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) | + 0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) | + 0x0200*(d is e)) + res = interpret(f, [0], type_system=self.ts) + assert res == 0x0004 + res = interpret(f, [1], type_system=self.ts) + assert res == 0x0020 + res = interpret(f, [2], type_system=self.ts) + assert res == 0x0100 + res = interpret(f, [3], type_system=self.ts) + assert res == 0x0200 + + def test_eq(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a == b) | 0x0002*(a == c) | 0x0004*(a == d) | + 0x0008*(a == e) | 0x0010*(b == c) | 0x0020*(b == d) | + 0x0040*(b == e) | 0x0080*(c == d) | 0x0100*(c == e) | + 0x0200*(d == e)) + res = interpret(f, [0], type_system=self.ts) + assert res == 0x0004 + res = interpret(f, [1], type_system=self.ts) + assert res == 0x0020 + res = interpret(f, [2], type_system=self.ts) + assert res == 0x0100 + res = interpret(f, [3]) + assert res == 0x0200 + + def test_istrue(self): + class A: + pass + def f(i): + if i == 0: + a = A() + else: + a = None + if a: + return 1 + else: + return 2 + res = interpret(f, [0], type_system=self.ts) + assert res == 1 + res = interpret(f, [1], type_system=self.ts) + assert res == 2 + + def test_ne(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a != b) | 0x0002*(a != c) | 0x0004*(a != d) | + 0x0008*(a != e) | 0x0010*(b != c) | 0x0020*(b != d) | + 0x0040*(b != e) | 0x0080*(c != d) | 0x0100*(c != e) | + 0x0200*(d != e)) + res = interpret(f, [0], type_system=self.ts) + assert res == ~0x0004 & 0x3ff + res = interpret(f, [1], type_system=self.ts) + assert res == ~0x0020 & 0x3ff + res = interpret(f, [2], type_system=self.ts) + assert res == ~0x0100 & 0x3ff + res = interpret(f, [3], type_system=self.ts) + assert res == ~0x0200 & 0x3ff + + def test_hash_preservation(self): + class C: + pass + class D(C): + pass + c = C() + d = D() + def f(): + d2 = D() + x = hash(d2) == id(d2) # xxx check for this CPython peculiarity for now + return x, hash(c)+hash(d) + + res = interpret(f, [], type_system=self.ts) + + assert res.item0 == True + assert res.item1 == intmask(hash(c)+hash(d)) + + def test_type(self): + class A: + pass + class B(A): + pass + def g(a): + return type(a) + def f(i): + if i > 0: + a = A() + elif i < 0: + a = B() + else: + a = None + return g(a) is A # should type(None) work? returns None for now + res = interpret(f, [1], type_system=self.ts) + assert res is True + res = interpret(f, [-1], type_system=self.ts) + assert res is False + res = interpret(f, [0], type_system=self.ts) + assert res is False + + def test_void_fnptr(self): + def g(): + return 42 + def f(): + e = EmptyBase() + e.attr = g + return e.attr() + res = interpret(f, [], type_system=self.ts) + assert res == 42 + + def test_getattr_on_classes(self): + class A: + def meth(self): + return self.value + 42 + class B(A): + def meth(self): + shouldnt**be**seen + class C(B): + def meth(self): + return self.value - 1 + def pick_class(i): + if i > 0: + return A + else: + return C + def f(i): + meth = pick_class(i).meth + x = C() + x.value = 12 + return meth(x) # calls A.meth or C.meth, completely ignores B.meth + res = interpret(f, [1], type_system=self.ts) + assert res == 54 + res = interpret(f, [0], type_system=self.ts) + assert res == 11 + + def test_constant_bound_method(self): + class C: + value = 1 + def meth(self): + return self.value + meth = C().meth + def f(): + return meth() + res = interpret(f, [], type_system=self.ts) + assert res == 1 def test__del__(): class A(object): @@ -434,3 +441,12 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None + + +class TestLltype(BaseTestRclass): + + ts = "lltype" + +class TestOotype(BaseTestRclass): + + ts = "ootype" From arigo at codespeak.net Thu Mar 2 18:12:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Mar 2006 18:12:33 +0100 (CET) Subject: [pypy-svn] r23918 - pypy/dist/pypy/jit/test Message-ID: <20060302171233.9564D100B6@code0.codespeak.net> Author: arigo Date: Thu Mar 2 18:12:23 2006 New Revision: 23918 Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: Stop generating skips for tests that are probably not relevant any more. Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/dist/pypy/jit/test/test_hint_annotation.py Thu Mar 2 18:12:23 2006 @@ -386,7 +386,7 @@ py.test.raises(HintError, hannotate, ll_getitem_switch, [annmodel.SomePtr(lltype.Ptr(S))]) -def test_invalid_hint_2(): +def undecided_relevance_test_invalid_hint_2(): S = lltype.GcStruct('S', ('x', lltype.Signed)) def ll_getitem_switch(s): if s.x > 0: # variable exitswitch Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Thu Mar 2 18:12:23 2006 @@ -211,7 +211,7 @@ graph2, insns = abstrinterp(ll_function, [s, 0, 0], [0, 1, 2]) assert insns == {} -def test_recursive_call(): +def no_longer_relevant_test_recursive_call(): py.test.skip("reimplement or remove the test: " "non-inlined calls with constant results") def ll_factorial(k): From goden at codespeak.net Thu Mar 2 18:37:03 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Thu, 2 Mar 2006 18:37:03 +0100 (CET) Subject: [pypy-svn] r23921 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20060302173703.9D06D100A8@code0.codespeak.net> Author: goden Date: Thu Mar 2 18:36:54 2006 New Revision: 23921 Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Log: (arigo, goden) - can now set the ".value" attribute of CTypes primitive types. Refactored the PrimitiveRepr to move duplicate llops to helper functions. Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/rprimitive.py Thu Mar 2 18:36:54 2006 @@ -3,7 +3,7 @@ from ctypes import c_double, c_char_p from pypy.annotation import model as annmodel from pypy.rpython import extregistry -from pypy.rpython.rmodel import Repr +from pypy.rpython.rmodel import Repr, inputconst from pypy.rpython.lltypesystem import lltype from pypy.annotation.pairtype import pairtype from pypy.rpython.rmodel import IntegerRepr @@ -25,44 +25,70 @@ ] class PrimitiveRepr(Repr): - def __init__(self, rtyper, type, ll_type): + def __init__(self, rtyper, ctype, ll_type): + self.ctype = ctype self.ll_type = ll_type self.lowleveltype = lltype.Ptr( - lltype.GcStruct( "CtypesBox_%s" % (type.__name__,), - ( "c_data", lltype.Struct('C_Data_%s' % (type.__name__,), + lltype.GcStruct( "CtypesBox_%s" % (ctype.__name__,), + ( "c_data", lltype.Struct('C_Data_%s' % (ctype.__name__,), ('value', ll_type) ) ) ) ) + self.const_cache = {} # store generated const values+original value + + def get_c_data(self, llops, v_primitive): + inputargs = [v_primitive, inputconst(lltype.Void, "c_data")] + return llops.genop('getsubstruct', inputargs, + lltype.Ptr(self.lowleveltype.TO.c_data) ) + + def setfield(self, llops, v_primitive, v_value): + v_c_data = self.get_c_data(llops, v_primitive) + cname = inputconst(lltype.Void, 'value') + llops.genop('setfield', [v_c_data, cname, v_value]) + + def getfield(self, llops, v_primitive): + v_c_data = self.get_c_data(llops, v_primitive) + + cname = inputconst(lltype.Void, 'value') + return llops.genop('getfield', [v_c_data, cname], + resulttype=self.ll_type) + + def convert_const(self, ctype_value): + assert isinstance(ctype_value, self.ctype) + key = id(ctype_value) + try: + return self.const_cache[key][0] + except KeyError: + p = lltype.malloc(self.lowleveltype.TO) + + self.const_cache[key] = p, ctype_value + p.c_data.value = ctype_value.value + return p + def rtype_getattr(self, hop): s_attr = hop.args_s[1] assert s_attr.is_constant() assert s_attr.const == 'value' v_primitive = hop.inputarg(self, 0) - cname = hop.inputconst(lltype.Void, 'value') - inputargs = [v_primitive, hop.inputconst(lltype.Void, "c_data")] - v_c_data = hop.genop('getsubstruct', - inputargs, - lltype.Ptr(self.lowleveltype.TO.c_data) ) - - return hop.genop('getfield', [v_c_data, cname], - resulttype=self.ll_type) + return self.getfield(hop.llops, v_primitive) + def rtype_setattr(self, hop): + s_attr = hop.args_s[1] + assert s_attr.is_constant() + assert s_attr.const == 'value' + v_primitive, v_attr, v_value = hop.inputargs(self, lltype.Void, + self.ll_type) + self.setfield(hop.llops, v_primitive, v_value) def primitive_specialize_call(hop): r_primitive = hop.r_result c1 = hop.inputconst(lltype.Void, r_primitive.lowleveltype.TO) v_result = hop.genop("malloc", [c1], resulttype=r_primitive.lowleveltype) - inputargs = [v_result, hop.inputconst(lltype.Void, "c_data")] - v_c_data = hop.genop('getsubstruct', - inputargs, - lltype.Ptr(r_primitive.lowleveltype.TO.c_data) ) - cname = hop.inputconst(lltype.Void, 'value') if len(hop.args_s): v_value, = hop.inputargs(r_primitive.ll_type) - - hop.genop('setfield', [v_c_data, cname, v_value]) + r_primitive.setfield(hop.llops, v_result, v_value) return v_result def do_register(the_type, ll_type): Modified: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Thu Mar 2 18:36:54 2006 @@ -35,7 +35,7 @@ if conftest.option.view: t.view() - def test_annotate_c_int_2(self): + def test_annotate_prebuilt_c_int(self): res = c_int(42) def func(): @@ -50,6 +50,22 @@ if conftest.option.view: t.view() + def test_annotate_set_c_int_value(self): + def func(): + res = c_int(42) + res.value = 52 + + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == int + + if conftest.option.view: + t.view() + class Test_specialization: def test_specialize_c_int(self): def create_c_int(): @@ -71,9 +87,43 @@ res = interpret(create_c_int, []) assert res == 42 + def test_specialize_c_int_set_value(self): + def set_c_int_value(): + ci = c_int(42) + ci.value = 52 + return ci.value + + res = interpret(set_c_int_value, []) + assert res == 52 + + def test_specialize_access_prebuilt_c_int_value(self): + ci = c_int(42) + def access_cint(): + return ci.value + + res = interpret(access_cint, []) + assert res == 42 + class Test_compilation: def test_compile_c_int(self): def create_c_int(): return c_int(42).value fn = compile(create_c_int, []) assert fn() == 42 + + def test_compile_prebuilt_c_int(self): + ci = c_int(42) + def access_cint(): + return ci.value + + fn = compile(access_cint, []) + assert fn() == 42 + + def test_compile_set_prebuilt_c_int_value(self): + ci = c_int(42) + def access_cint(): + ci.value = 52 + return ci.value + + fn = compile(access_cint, []) + assert fn() == 52 From arigo at codespeak.net Thu Mar 2 18:49:47 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Mar 2006 18:49:47 +0100 (CET) Subject: [pypy-svn] r23923 - pypy/dist/pypy/rpython/test Message-ID: <20060302174947.464B7100A8@code0.codespeak.net> Author: arigo Date: Thu Mar 2 18:49:46 2006 New Revision: 23923 Modified: pypy/dist/pypy/rpython/test/test_llinterp.py Log: Oups, the last test failed if you run more than 4 tests before. Added an official and safe way to clear the getinterpreter() cache. Modified: pypy/dist/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_llinterp.py (original) +++ pypy/dist/pypy/rpython/test/test_llinterp.py Thu Mar 2 18:49:46 2006 @@ -65,6 +65,10 @@ _lastinterpreted = [] _tcache = {} +def clear_tcache(): + del _lastinterpreted[:] + _tcache.clear() + def get_interpreter(func, values, view='auto', viewbefore='auto', policy=None, someobjects=False, type_system="lltype"): key = (func,) + tuple([typeOf(x) for x in values])+ (someobjects,) @@ -427,7 +431,7 @@ def test_cleanup_finally(): interp, graph = get_interpreter(cleanup_f, [-1]) - _tcache.clear() # because we hack the graph in place + clear_tcache() # because we hack the graph in place operations = graph.startblock.operations assert operations[0].opname == "direct_call" assert operations[1].opname == "direct_call" @@ -452,7 +456,7 @@ def test_cleanup_except(): interp, graph = get_interpreter(cleanup_f, [-1]) - _tcache.clear() # because we hack the graph in place + clear_tcache() # because we hack the graph in place operations = graph.startblock.operations assert operations[0].opname == "direct_call" assert operations[1].opname == "direct_call" From rxe at codespeak.net Thu Mar 2 19:01:20 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 2 Mar 2006 19:01:20 +0100 (CET) Subject: [pypy-svn] r23924 - pypy/dist/pypy/translator/llvm Message-ID: <20060302180120.BF0BF100B2@code0.codespeak.net> Author: rxe Date: Thu Mar 2 19:01:18 2006 New Revision: 23924 Modified: pypy/dist/pypy/translator/llvm/structnode.py Log: Somehow forgot check this in yesterday. Modified: pypy/dist/pypy/translator/llvm/structnode.py ============================================================================== --- pypy/dist/pypy/translator/llvm/structnode.py (original) +++ pypy/dist/pypy/translator/llvm/structnode.py Thu Mar 2 19:01:18 2006 @@ -2,6 +2,16 @@ from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode from pypy.rpython.lltypesystem import lltype +def getindexhelper(name, struct): + assert name in list(struct._names) + + fieldnames = struct._names_without_voids() + try: + index = fieldnames.index(name) + except ValueError: + index = -1 + return index + log = log.structnode class StructTypeNode(LLVMNode): From nik at codespeak.net Thu Mar 2 19:20:41 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 2 Mar 2006 19:20:41 +0100 (CET) Subject: [pypy-svn] r23925 - in pypy/dist/pypy: annotation rpython/ootypesystem rpython/test Message-ID: <20060302182041.4E2FA100A9@code0.codespeak.net> Author: nik Date: Thu Mar 2 19:20:36 2006 New Revision: 23925 Modified: pypy/dist/pypy/annotation/description.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/rpbc.py pypy/dist/pypy/rpython/test/test_rclass.py Log: (pedronis, nik) fixed __del__ support in ootypesystem. __del__ is simply rtyped with a flag "finalizer", the backends are responsible for taking appropriate measures. fixed a horribly subtle bug in annotation, where emulated calls to __del__ methods were not correctly recorded. Modified: pypy/dist/pypy/annotation/description.py ============================================================================== --- pypy/dist/pypy/annotation/description.py (original) +++ pypy/dist/pypy/annotation/description.py Thu Mar 2 19:20:36 2006 @@ -398,7 +398,7 @@ from pypy.annotation.model import s_None, SomeInstance s_func = self.s_read_attribute('__del__') args_s = [SomeInstance(classdef)] - s = self.bookkeeper.emulate_pbc_call(None, s_func, args_s) + s = self.bookkeeper.emulate_pbc_call(classdef, s_func, args_s) assert s_None.contains(s) return classdef Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Thu Mar 2 19:20:36 2006 @@ -214,14 +214,16 @@ raise TyperError("class attribute overrides method") allclassattributes[mangled] = name, s_value - if '__init__' not in selfattrs and \ - self.classdef.classdesc.find_source_for("__init__") is not None: - s_init = self.classdef.classdesc.s_get_value(self.classdef, - '__init__') - if isinstance(s_init, annmodel.SomePBC): - mangled = mangle("__init__") - allmethods[mangled] = "__init__", s_init - # else: it's the __init__ of a builtin exception + special_methods = ["__init__", "__del__"] + for meth_name in special_methods: + if meth_name not in selfattrs and \ + self.classdef.classdesc.find_source_for(meth_name) is not None: + s_meth = self.classdef.classdesc.s_get_value(self.classdef, + meth_name) + if isinstance(s_meth, annmodel.SomePBC): + mangled = mangle(meth_name) + allmethods[mangled] = meth_name, s_meth + # else: it's the __init__ of a builtin exception # # hash() support @@ -259,7 +261,8 @@ # get method implementation from pypy.rpython.ootypesystem.rpbc import MethodImplementations methimpls = MethodImplementations.get(self.rtyper, s_value) - m_impls = methimpls.get_impl(mangled, methdesc) + m_impls = methimpls.get_impl(mangled, methdesc, + is_finalizer=name == "__del__") methods.update(m_impls) Modified: pypy/dist/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rpbc.py Thu Mar 2 19:20:36 2006 @@ -101,14 +101,17 @@ return methodsimpl get = staticmethod(get) - def get_impl(self, name, methdesc): + def get_impl(self, name, methdesc, is_finalizer=False): impls = {} + flags = {} + if is_finalizer: + flags['finalizer'] = True for rowname, (row, M) in self.row_mapping.iteritems(): if methdesc is None: - m = ootype.meth(M, _name=name, abstract=True) + m = ootype.meth(M, _name=name, abstract=True, **flags) else: impl_graph = row[methdesc.funcdesc].graph - m = ootype.meth(M, _name=name, graph=impl_graph) + m = ootype.meth(M, _name=name, graph=impl_graph, **flags) derived_name = row_method_name(name, rowname) impls[derived_name] = m return impls Modified: pypy/dist/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rclass.py (original) +++ pypy/dist/pypy/rpython/test/test_rclass.py Thu Mar 2 19:20:36 2006 @@ -377,76 +377,132 @@ res = interpret(f, [], type_system=self.ts) assert res == 1 -def test__del__(): - class A(object): - def __init__(self): - self.a = 2 - def __del__(self): - self.a = 3 - def f(): - a = A() - return a.a - t = TranslationContext() - t.buildannotator().build_types(f, []) - t.buildrtyper().specialize() - graph = graphof(t, f) - TYPE = graph.startblock.operations[0].args[0].value - RTTI = getRuntimeTypeInfo(TYPE) - queryptr = RTTI._obj.query_funcptr # should not raise - destrptr = RTTI._obj.destructor_funcptr - assert destrptr is not None - -def test_del_inheritance(): - class State: - pass - s = State() - s.a_dels = 0 - s.b_dels = 0 - class A(object): - def __del__(self): - s.a_dels += 1 - class B(A): - def __del__(self): - s.b_dels += 1 - class C(A): - pass - def f(): - A() - B() - C() - A() - B() - C() - return s.a_dels * 10 + s.b_dels - res = f() - assert res == 42 - t = TranslationContext() - t.buildannotator().build_types(f, []) - t.buildrtyper().specialize() - graph = graphof(t, f) - TYPEA = graph.startblock.operations[0].args[0].value - RTTIA = getRuntimeTypeInfo(TYPEA) - TYPEB = graph.startblock.operations[3].args[0].value - RTTIB = getRuntimeTypeInfo(TYPEB) - TYPEC = graph.startblock.operations[6].args[0].value - RTTIC = getRuntimeTypeInfo(TYPEC) - queryptra = RTTIA._obj.query_funcptr # should not raise - queryptrb = RTTIB._obj.query_funcptr # should not raise - queryptrc = RTTIC._obj.query_funcptr # should not raise - destrptra = RTTIA._obj.destructor_funcptr - destrptrb = RTTIB._obj.destructor_funcptr - destrptrc = RTTIC._obj.destructor_funcptr - assert destrptra == destrptrc - assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] - assert destrptra is not None - assert destrptrb is not None - class TestLltype(BaseTestRclass): ts = "lltype" + def test__del__(self): + class A(object): + def __init__(self): + self.a = 2 + def __del__(self): + self.a = 3 + def f(): + a = A() + return a.a + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper().specialize() + graph = graphof(t, f) + TYPE = graph.startblock.operations[0].args[0].value + RTTI = getRuntimeTypeInfo(TYPE) + queryptr = RTTI._obj.query_funcptr # should not raise + destrptr = RTTI._obj.destructor_funcptr + assert destrptr is not None + + def test_del_inheritance(self): + class State: + pass + s = State() + s.a_dels = 0 + s.b_dels = 0 + class A(object): + def __del__(self): + s.a_dels += 1 + class B(A): + def __del__(self): + s.b_dels += 1 + class C(A): + pass + def f(): + A() + B() + C() + A() + B() + C() + return s.a_dels * 10 + s.b_dels + res = f() + assert res == 42 + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper().specialize() + graph = graphof(t, f) + TYPEA = graph.startblock.operations[0].args[0].value + RTTIA = getRuntimeTypeInfo(TYPEA) + TYPEB = graph.startblock.operations[3].args[0].value + RTTIB = getRuntimeTypeInfo(TYPEB) + TYPEC = graph.startblock.operations[6].args[0].value + RTTIC = getRuntimeTypeInfo(TYPEC) + queryptra = RTTIA._obj.query_funcptr # should not raise + queryptrb = RTTIB._obj.query_funcptr # should not raise + queryptrc = RTTIC._obj.query_funcptr # should not raise + destrptra = RTTIA._obj.destructor_funcptr + destrptrb = RTTIB._obj.destructor_funcptr + destrptrc = RTTIC._obj.destructor_funcptr + assert destrptra == destrptrc + assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] + assert destrptra is not None + assert destrptrb is not None + class TestOotype(BaseTestRclass): ts = "ootype" + + def test__del__(self): + class A(object): + def __init__(self): + self.a = 2 + def __del__(self): + self.a = 3 + def f(): + a = A() + return a.a + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper(type_system=self.ts).specialize() + graph = graphof(t, f) + TYPE = graph.startblock.operations[0].args[0].value + meth = TYPE._lookup("o__del___variant0") + assert meth.finalizer + + def test_del_inheritance(self): + class State: + pass + s = State() + s.a_dels = 0 + s.b_dels = 0 + class A(object): + def __del__(self): + s.a_dels += 1 + class B(A): + def __del__(self): + s.b_dels += 1 + class C(A): + pass + def f(): + A() + B() + C() + A() + B() + C() + return s.a_dels * 10 + s.b_dels + res = f() + assert res == 42 + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper(type_system=self.ts).specialize() + graph = graphof(t, f) + TYPEA = graph.startblock.operations[0].args[0].value + TYPEB = graph.startblock.operations[2].args[0].value + TYPEC = graph.startblock.operations[4].args[0].value + destra = TYPEA._lookup("o__del___variant0") + destrb = TYPEB._lookup("o__del___variant0") + destrc = TYPEC._lookup("o__del___variant0") + assert destra == destrc + assert destrb is not None + assert destra is not None + From goden at codespeak.net Thu Mar 2 19:25:46 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Thu, 2 Mar 2006 19:25:46 +0100 (CET) Subject: [pypy-svn] r23926 - in pypy/dist/pypy: annotation rpython/rctypes rpython/rctypes/test Message-ID: <20060302182546.AFF22100A9@code0.codespeak.net> Author: goden Date: Thu Mar 2 19:25:37 2006 New Revision: 23926 Modified: pypy/dist/pypy/annotation/binaryop.py pypy/dist/pypy/rpython/rctypes/rarray.py pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Log: (arigo, goden) - renabled some rarray tests after teaching annotation/binaryop.py about values in the extregistry to correctly convert c_longs returned by array indexing to ints. Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Thu Mar 2 19:25:37 2006 @@ -16,9 +16,11 @@ from pypy.annotation.model import SomeCTypesObject from pypy.annotation.model import unionof, UnionError, set, missing_operation, TLS from pypy.annotation.model import add_knowntypedata, merge_knowntypedata +from pypy.annotation.model import lltype_to_annotation from pypy.annotation.bookkeeper import getbookkeeper from pypy.objspace.flow.model import Variable from pypy.annotation.listdef import ListDef +from pypy.rpython import extregistry # convenience only! def immutablevalue(x): @@ -761,6 +763,10 @@ # are those having memorystate NOMEMORY return s_cto.knowntype._type_.annotator_type except AttributeError: + if extregistry.is_registered_type(s_cto.knowntype._type_): + entry = extregistry.lookup_type(s_cto.knowntype._type_) + return lltype_to_annotation(entry.lowleveltype) + return SomeCTypesObject( s_cto.knowntype._type_, memorystate=s_cto.memorystate) Modified: pypy/dist/pypy/rpython/rctypes/rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/rarray.py Thu Mar 2 19:25:37 2006 @@ -56,8 +56,7 @@ def arraytype_compute_annotation(metatype, type): def compute_result_annotation(*arg_s): return SomeCTypesObject(type, SomeCTypesObject.OWNSMEMORY) - return SomeBuiltin(compute_result_annotation, - methodname=type.__name__) + return SomeBuiltin(compute_result_annotation, methodname=type.__name__) extregistry.register_type(ArrayType, compute_annotation=arraytype_compute_annotation, Modified: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Thu Mar 2 19:25:37 2006 @@ -19,7 +19,7 @@ c_int_10 = ARRAY(c_int,10) c_int_p_test = POINTER(c_int) -py.test.skip("Reworking primitive types") +#py.test.skip("Reworking primitive types") class Test_annotation: def test_annotate_array(self): @@ -49,7 +49,7 @@ if conftest.option.view: t.view() - def test_annotate_pointer_access_as_array(self): + def x_test_annotate_pointer_access_as_array(self): """ Make sure that pointers work the same way as arrays, for ctypes compatibility. @@ -74,7 +74,7 @@ assert s.knowntype == int #d#t.view() - def test_annotate_array_slice_access(self): + def x_test_annotate_array_slice_access(self): def slice_access(): my_array = c_int_10() #f#my_array[0:7] = c_int(1) * 7 @@ -127,7 +127,7 @@ py.test.raises(IndexError, "s = a.build_types(access_with_invalid_negative_index,[])") class Test_specialization: - def test_specialize_array(self): + def x_test_specialize_array(self): def create_array(): return c_int_10() @@ -138,7 +138,7 @@ py.test.raises(IndexError, "c_data[10]") py.test.raises(TypeError, "len(c_data)") - def test_specialize_array_access(self): + def x_test_specialize_array_access(self): def access_array(): my_array = c_int_10() my_array[0] = 1 From ale at codespeak.net Thu Mar 2 19:26:37 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 2 Mar 2006 19:26:37 +0100 (CET) Subject: [pypy-svn] r23927 - in pypy/dist/pypy: interpreter/pyparser module/recparser Message-ID: <20060302182637.99647100A9@code0.codespeak.net> Author: ale Date: Thu Mar 2 19:26:33 2006 New Revision: 23927 Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py pypy/dist/pypy/module/recparser/pyparser.py Log: (arre, ale, stuart) Some changes to make the parser/compiler translatable again. There are more needed though. Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/pythonparse.py (original) +++ pypy/dist/pypy/interpreter/pyparser/pythonparse.py Thu Mar 2 19:26:33 2006 @@ -59,7 +59,8 @@ goalnumber = self.symbols.sym_values[goal] target = self.rules[goalnumber] src = Source(lines, flags) - + + result = None try: result = target.match(src, builder) except AlternateGrammarException: # handle from __future__ import with_statement Modified: pypy/dist/pypy/module/recparser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/recparser/pyparser.py (original) +++ pypy/dist/pypy/module/recparser/pyparser.py Thu Mar 2 19:26:33 2006 @@ -10,7 +10,7 @@ from pypy.interpreter.pyparser.syntaxtree import TokenNode, SyntaxNode, AbstractSyntaxVisitor from pypy.interpreter.pyparser.pythonutil import PYTHON_PARSER from pypy.interpreter.pyparser.error import SyntaxError -from pypy.interpreter.pyparser import grammar, pysymbol, pytoken +from pypy.interpreter.pyparser import grammar, symbol, pytoken from pypy.interpreter.argument import Arguments @@ -94,14 +94,14 @@ Returns true if the root node in the syntax tree is an expr node, false otherwise. """ - return self.node.name == pysymbol.eval_input + return self.node.name == symbol.eval_input def issuite(self): """STType.issuite() Returns true if the root node in the syntax tree is a suite node, false otherwise. """ - return self.node.name == pysymbol.file_input + return self.node.name == symbol.file_input def descr_compile(self, w_filename = ""): """STType.compile() @@ -226,8 +226,8 @@ def descr_grammarelement_repr( self, space ): """TODO: make __repr__ RPython""" - import pysymbol - return space.wrap( self.display(0, pysymbol.sym_name) ) + import symbol + return space.wrap( self.display(0, symbol.sym_name) ) def descr_grammarelement_get_children( self, space ): return space.newlist( [ space.wrap(it) for it in self.args ] ) From rxe at codespeak.net Thu Mar 2 19:35:47 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 2 Mar 2006 19:35:47 +0100 (CET) Subject: [pypy-svn] r23928 - pypy/dist/pypy/tool Message-ID: <20060302183547.B6FD1100AC@code0.codespeak.net> Author: rxe Date: Thu Mar 2 19:35:44 2006 New Revision: 23928 Modified: pypy/dist/pypy/tool/isolate.py Log: Missing attribute needed by repr in IsolateInvoker Modified: pypy/dist/pypy/tool/isolate.py ============================================================================== --- pypy/dist/pypy/tool/isolate.py (original) +++ pypy/dist/pypy/tool/isolate.py Thu Mar 2 19:35:44 2006 @@ -28,6 +28,7 @@ _closed = False def __init__(self, module): + self.module = module self.slave = slaveproc.SlaveProcess(os.path.join(os.path.dirname(__file__), 'isolate_slave.py')) res = self.slave.cmd(('load', module)) From rxe at codespeak.net Thu Mar 2 19:46:42 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 2 Mar 2006 19:46:42 +0100 (CET) Subject: [pypy-svn] r23929 - pypy/dist/pypy/translator/llvm/demo Message-ID: <20060302184642.25865100AC@code0.codespeak.net> Author: rxe Date: Thu Mar 2 19:46:39 2006 New Revision: 23929 Modified: pypy/dist/pypy/translator/llvm/demo/bpnn.py Log: Cleanup Modified: pypy/dist/pypy/translator/llvm/demo/bpnn.py ============================================================================== --- pypy/dist/pypy/translator/llvm/demo/bpnn.py (original) +++ pypy/dist/pypy/translator/llvm/demo/bpnn.py Thu Mar 2 19:46:39 2006 @@ -221,8 +221,6 @@ return 0 #_________________________________________________________ - -from pypy.translator.llvm.genllvm import compile_function if __name__ == "__main__": from pypy.translator.llvm.demo.run import run From rxe at codespeak.net Thu Mar 2 19:47:42 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 2 Mar 2006 19:47:42 +0100 (CET) Subject: [pypy-svn] r23930 - pypy/dist/pypy/translator/llvm Message-ID: <20060302184742.1D791100B2@code0.codespeak.net> Author: rxe Date: Thu Mar 2 19:47:38 2006 New Revision: 23930 Modified: pypy/dist/pypy/translator/llvm/buildllvm.py pypy/dist/pypy/translator/llvm/genllvm.py Log: Use isolate to import modules (and run tests). Modified: pypy/dist/pypy/translator/llvm/buildllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/buildllvm.py (original) +++ pypy/dist/pypy/translator/llvm/buildllvm.py Thu Mar 2 19:47:38 2006 @@ -142,21 +142,11 @@ fdump.close() log.build(data) raise - # XXX do we need to do some check on fout/ferr? - # XXX not a nice way to import a module - if pyxfile: - log.build("inserting path to sys.path", dirpath) - sys.path.insert(0, '.') - cmd = "import %(modname)s as testmodule" % locals() - log.build(cmd) - exec cmd - sys.path.pop(0) finally: os.chdir(str(lastdir)) if pyxfile: - log.build("modname", modname) - return testmodule + return modname, str(dirpath) if exe_name: exe_path = str(llvmfile.dirpath().join(exe_name)) Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Thu Mar 2 19:47:38 2006 @@ -1,5 +1,7 @@ import time +from pypy.tool import isolate + from pypy.translator.llvm import buildllvm from pypy.translator.llvm.database import Database from pypy.translator.llvm.pyxwrapper import write_pyx_wrapper @@ -249,15 +251,20 @@ basename = self.filename.purebasename + '_wrapper' + postfix + '.pyx' pyxfile = self.filename.new(basename = basename) write_pyx_wrapper(self, pyxfile) - res = buildllvm.make_module_from_llvm(self, self.filename, - pyxfile=pyxfile, - optimize=optimize) - wrap_fun = getattr(res, 'pypy_' + self.entry_func_name + "_wrapper") + info = buildllvm.make_module_from_llvm(self, self.filename, + pyxfile=pyxfile, + optimize=optimize) + + mod, wrap_fun = self.isolate_module(*info) if return_fn: return wrap_fun + return mod, wrap_fun - return res, wrap_fun - + def isolate_module(self, modname, dirpath): + ext_module = isolate.Isolate((dirpath, modname)) + wrap_fun = getattr(ext_module, 'pypy_' + self.entry_func_name + "_wrapper") + return ext_module, wrap_fun + def _checkpoint(self, msg=None): if not self.logging: return @@ -319,7 +326,3 @@ if view or conftest.option.view: t.view() return genllvm(t, function, optimize=optimize, **kwds) - -def compile_function(function, annotation, **kwds): - """ Helper - which get the compiled module from CPython. """ - return compile_module(function, annotation, return_fn=True, **kwds) From pedronis at codespeak.net Thu Mar 2 19:48:50 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 2 Mar 2006 19:48:50 +0100 (CET) Subject: [pypy-svn] r23931 - pypy/dist/pypy/rpython/test Message-ID: <20060302184850.9F6C7100B0@code0.codespeak.net> Author: pedronis Date: Thu Mar 2 19:48:48 2006 New Revision: 23931 Modified: pypy/dist/pypy/rpython/test/test_rclass.py Log: added test Modified: pypy/dist/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rclass.py (original) +++ pypy/dist/pypy/rpython/test/test_rclass.py Thu Mar 2 19:48:48 2006 @@ -57,6 +57,27 @@ res = interpret(dummyfn, [], type_system=self.ts) assert res == 12 + def test_classattr_both(self): + print self.ts + class A: + a = 1 + class B(A): + a = 2 + def pick(i): + if i == 0: + return A + else: + return B + + def dummyfn(i): + C = pick(i) + i = C() + return C.a + i.a + res = interpret(dummyfn, [0], type_system=self.ts) + assert res == 2 + res = interpret(dummyfn, [1], type_system=self.ts) + assert res == 4 + def test_classattr_as_defaults(self): def dummyfn(): x = Random() From arigo at codespeak.net Fri Mar 3 15:25:02 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Mar 2006 15:25:02 +0100 (CET) Subject: [pypy-svn] r23945 - in pypy/dist/pypy/objspace/flow: . test Message-ID: <20060303142502.41E64100B6@code0.codespeak.net> Author: arigo Date: Fri Mar 3 15:24:54 2006 New Revision: 23945 Modified: pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/objspace/flow/test/test_objspace.py Log: Yuk! The ages-old extract_cell_content() hack is buggy. It crashes if the nested scope cell in question contains an object with a custom __cmp__ -- it was fine with a custom __eq__ only. Who can claim he knows the order in which Python tries to call __cmp__ and __eq__ in all situations? Bug found because lladdress.address has a custom __cmp__, so the flow space crashes on any helper that gets the NULL address object via a closure. Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Fri Mar 3 15:24:54 2006 @@ -508,8 +508,12 @@ the func_closure of a function object.""" # yuk! this is all I could come up with that works in Python 2.2 too class X(object): + def __cmp__(self, other): + self.other = other + return 0 def __eq__(self, other): self.other = other + return True x = X() x_cell, = (lambda: x).func_closure x_cell == c Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Fri Mar 3 15:24:54 2006 @@ -4,6 +4,7 @@ from pypy.interpreter.argument import Arguments from pypy.translator.simplify import simplify_graph from pypy.objspace.flow import FlowObjSpace +from pypy.objspace.flow import objspace import os import operator @@ -641,3 +642,14 @@ def user_defined_function(): pass + + +def test_extract_cell_content(): + class Strange(object): + def __cmp__(self, other): + assert False, "should not be called" + strange = Strange() + def f(): + return strange + res = objspace.extract_cell_content(f.func_closure[0]) + assert res is strange From arigo at codespeak.net Fri Mar 3 16:31:31 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Mar 2006 16:31:31 +0100 (CET) Subject: [pypy-svn] r23947 - pypy/dist/pypy/doc Message-ID: <20060303153131.F129F100BC@code0.codespeak.net> Author: arigo Date: Fri Mar 3 16:31:20 2006 New Revision: 23947 Modified: pypy/dist/pypy/doc/svn-help.txt Log: Link to the subversion FAQ about configuring http proxies (thanks __ab__). Modified: pypy/dist/pypy/doc/svn-help.txt ============================================================================== --- pypy/dist/pypy/doc/svn-help.txt (original) +++ pypy/dist/pypy/doc/svn-help.txt Fri Mar 3 16:31:20 2006 @@ -120,6 +120,9 @@ http: in the subversion URL. This will make use of SSL encryption, which cannot be intercepted by proxies. +Alternatively, if you want to change your proxy configuration, see the +subversion FAQ: http://subversion.tigris.org/faq.html#proxy + How to Avoid Line-ending Hell ----------------------------- From arigo at codespeak.net Fri Mar 3 16:31:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Mar 2006 16:31:50 +0100 (CET) Subject: [pypy-svn] r23948 - in pypy/dist/pypy: rpython/memory translator/c translator/c/test Message-ID: <20060303153150.3E7CD100BC@code0.codespeak.net> Author: arigo Date: Fri Mar 3 16:31:47 2006 New Revision: 23948 Modified: pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/database.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: Intermediate check-in: getting close to translating the MarkSweepGC. Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Fri Mar 3 16:31:47 2006 @@ -87,7 +87,7 @@ def __init__(self, dummy=None, get_roots=None): self.get_roots = get_roots - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) def malloc(self, typeid, length=0): size = self.fixed_size(typeid) @@ -115,7 +115,7 @@ #need to maintain a list of malloced objects, since we used the systems #allocator and can't walk the heap self.malloced_objects = AddressLinkedList() - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots def malloc(self, typeid, length=0): @@ -224,7 +224,7 @@ self.top_of_space = self.tospace + space_size self.fromspace = raw_malloc(space_size) self.free = self.tospace - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots def free_memory(self): @@ -359,7 +359,7 @@ self.zero_ref_counts = AddressLinkedList() self.length_zero_ref_counts = 0 self.max_refcount_zero = max_refcount_zero - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots self.collecting = False Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Fri Mar 3 16:31:47 2006 @@ -88,10 +88,20 @@ for var in block.inputargs: if var_needsgc(var): newops.extend(self.push_alive(var)) + # XXX this is getting obscure. Maybe we should use the basic + # graph-transforming capabilities of the RTyper instead, as we + # seem to run into all the same problems as the ones we already + # had to solve there. + num_ops_after_exc_raising = 0 for op in block.operations: - ops, cleanup_before_exception = self.replacement_operations(op, livevars) + num_ops_after_exc_raising = 0 + res = self.replacement_operations(op, livevars) + try: + ops, cleanup_before_exception = res + except ValueError: + ops, cleanup_before_exception, num_ops_after_exc_raising = res newops.extend(ops) - op = ops[-1] + op = ops[-1-num_ops_after_exc_raising] # XXX for now we assume that everything can raise if 1 or op.opname in EXCEPTION_RAISING_OPS: if tuple(livevars) in livevars2cleanup: @@ -103,9 +113,12 @@ cleanup_on_exception = tuple(cleanup_on_exception) livevars2cleanup[tuple(livevars)] = cleanup_on_exception op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception + op = ops[-1] if var_needsgc(op.result): if op.opname not in ('direct_call', 'indirect_call') and not var_ispyobj(op.result): - newops.extend(self.push_alive(op.result)) + lst = list(self.push_alive(op.result)) + newops.extend(lst) + num_ops_after_exc_raising += len(lst) livevars.append(op.result) if len(block.exits) == 0: # everything is fine already for returnblocks and exceptblocks @@ -117,6 +130,15 @@ # to the block, even if the variable dies in all # linked blocks. deadinallexits = sets.Set([]) + if num_ops_after_exc_raising > 0: + # No place to put the remaining pending operations! + # Need a new block along the non-exceptional link. + # XXX test this. + tail = newops[-num_ops_after_exc_raising:] + del newops[-num_ops_after_exc_raising:] + link = block.exits[0] + assert link.exitcase is None + insert_empty_block(self.translator, link, tail) else: deadinallexits = sets.Set(livevars) for link in block.exits: @@ -608,9 +630,53 @@ def __init__(self, translator): super(FrameworkGCTransformer, self).__init__(translator) class GCData(object): + from pypy.rpython.memory.gc import MarkSweepGC as GCClass startheapsize = 640*1024 # XXX adjust rootstacksize = 640*1024 # XXX adjust + + # types of the GC information tables + OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed) + TYPE_INFO = lltype.Struct("type_info", + ("fixedsize", lltype.Signed), + ("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)), + ("varitemsize", lltype.Signed), + ("ofstovar", lltype.Signed), + ("ofstolength", lltype.Signed), + ("varofstoptrs",lltype.Ptr(OFFSETS_TO_GC_PTR)), + ) + TYPE_INFO_TABLE = lltype.Array(TYPE_INFO) + + def q_is_varsize(typeid): + return gcdata.type_info_table[typeid].varitemsize != 0 + + def q_offsets_to_gc_pointers(typeid): + return gcdata.type_info_table[typeid].ofstoptrs + + def q_fixed_size(typeid): + return gcdata.type_info_table[typeid].fixedsize + + def q_varsize_item_sizes(typeid): + return gcdata.type_info_table[typeid].varitemsize + + def q_varsize_offset_to_variable_part(typeid): + return gcdata.type_info_table[typeid].ofstovar + + def q_varsize_offset_to_length(typeid): + return gcdata.type_info_table[typeid].ofstolength + + def q_varsize_offsets_to_gcpointers_in_var_part(typeid): + return gcdata.type_info_table[typeid].varofstoptrs + gcdata = GCData() + # set up dummy a table, to be overwritten with the real one in finish() + gcdata.type_info_table = lltype.malloc(GCData.TYPE_INFO_TABLE, 0, + immortal=True) + self.gcdata = gcdata + self.type_info_list = [] + self.id_of_type = {} # {LLTYPE: type_id} + self.offsettable_cache = {} + self.malloc_fnptr_cache = {} + sizeofaddr = llmemory.sizeof(llmemory.Address) from pypy.rpython.memory.lladdress import NULL @@ -628,11 +694,19 @@ return NULL def frameworkgc_setup(): + # run-time initialization code stackbase = lladdress.raw_malloc(GCData.rootstacksize) gcdata.root_stack_top = stackbase gcdata.root_stack_base = stackbase -# from pypy.rpython.memory.gc import MarkSweepGC -# gcdata.gc = MarkSweepGC(GCData.startheapsize, StackRootIterator) + gcdata.gc = GCData.GCClass(GCData.startheapsize, StackRootIterator) + gcdata.gc.set_query_functions( + q_is_varsize, + q_offsets_to_gc_pointers, + q_fixed_size, + q_varsize_item_sizes, + q_varsize_offset_to_variable_part, + q_varsize_offset_to_length, + q_varsize_offsets_to_gcpointers_in_var_part) def push_root(addr): top = gcdata.root_stack_top @@ -653,11 +727,20 @@ annmodel.s_None) pop_root_graph = annhelper.getgraph(pop_root, [], annmodel.SomeAddress()) + bk = self.translator.annotator.bookkeeper + classdef = bk.getuniqueclassdef(GCData.GCClass) + s_gcdata = annmodel.SomeInstance(classdef) + malloc_graph = annhelper.getgraph(GCData.GCClass.malloc.im_func, + [s_gcdata, + annmodel.SomeInteger(nonneg=True), + annmodel.SomeInteger(nonneg=True)], + annmodel.SomeAddress()) annhelper.finish() # at this point, annotate all mix-level helpers self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph, attach_empty_cleanup=True) self.push_root_ptr = self.graph2funcptr(push_root_graph) self.pop_root_ptr = self.graph2funcptr(pop_root_graph) + self.malloc_ptr = self.graph2funcptr(malloc_graph) def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True @@ -665,6 +748,71 @@ MinimalGCTransformer(self.translator).transform_graph(graph) return const_funcptr_fromgraph(graph) + def get_type_id(self, TYPE): + try: + return self.id_of_type[TYPE] + except KeyError: + assert not self.finished + assert isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)) + # Record the new type_id description as a small dict for now. + # It will be turned into a Struct("type_info") in finish() + type_id = len(self.type_info_list) + info = {} + self.type_info_list.append(info) + self.id_of_type[TYPE] = type_id + offsets = offsets_to_gc_pointers(TYPE) + info["ofstoptrs"] = self.offsets2table(offsets) + if not TYPE._is_varsize(): + info["fixedsize"] = llmemory.sizeof(TYPE) + else: + info["fixedsize"] = llmemory.sizeof(TYPE, 0) + if isinstance(TYPE, lltype.Struct): + ARRAY = TYPE._flds[TYPE._arrayfld] + ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld) + info["ofstolength"] = ofs1 + info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) + else: + ARRAY = TYPE + info["ofstolength"] = 0 + info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0) + assert isinstance(ARRAY, lltype.Array) + offsets = offsets_to_gc_pointers(ARRAY.OF) + info["varofstoptrs"] = self.offsets2table(offsets) + info["varitemsize"] = llmemory.sizeof(ARRAY.OF) + return type_id + + def offsets2table(self, offsets): + key = tuple(offsets) + try: + return self.offsettable_cache[key] + except KeyError: + cachedarray = lltype.malloc(self.gcdata.OFFSETS_TO_GC_PTR, + len(offsets), immortal=True) + for i, value in enumerate(offsets): + cachedarray[i] = value + self.offsettable_cache[key] = cachedarray + return cachedarray + + def finish(self): + newgcdependencies = super(FrameworkGCTransformer, self).finish() + if self.type_info_list is not None: + table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, + len(self.type_info_list), immortal=True) + for tableentry, newcontent in zip(table, self.type_info_list): + for key, value in newcontent.items(): + setattr(tableentry, key, value) + self.type_info_list = None + self.offsettable_cache = None + # replace the type_info_table pointer in gcdata -- at this point, + # the database is in principle complete, so it has already seen + # the old (empty) array. We need to force it to consider the new + # array now. It's a bit hackish as the old empty array will also + # be generated in the C source, but that's a rather minor problem. + self.gcdata.type_info_table = table + newgcdependencies = newgcdependencies or [] + newgcdependencies.append(table) + return newgcdependencies + def protect_roots(self, op, livevars): livevars = [var for var in livevars if not var_ispyobj(var)] newops = list(self.push_roots(livevars)) @@ -673,8 +821,27 @@ replace_direct_call = protect_roots replace_indirect_call = protect_roots - replace_malloc = protect_roots - replace_malloc_varsize = protect_roots + + def replace_malloc(self, op, livevars): + TYPE = op.args[0].value + PTRTYPE = op.result.concretetype + assert PTRTYPE.TO == TYPE + type_id = self.get_type_id(TYPE) + + v = varoftype(llmemory.Address) + c_type_id = rmodel.inputconst(lltype.Signed, type_id) + if len(op.args) == 1: + v_length = rmodel.inputconst(lltype.Signed, 0) + else: + v_length = op.args[1] + newop = SpaceOperation("direct_call", + [self.malloc_ptr, c_type_id, v_length], + v) + ops, finally_ops = self.protect_roots(newop, livevars) + ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result)) + return ops, finally_ops, 1 + + replace_malloc_varsize = replace_malloc def push_alive_nopyobj(self, var): return [] @@ -697,6 +864,25 @@ yield SpaceOperation("gc_reload_possibly_moved", [v, var], varoftype(lltype.Void)) +# XXX copied and modified from lltypelayout.py +def offsets_to_gc_pointers(TYPE): + offsets = [] + if isinstance(TYPE, lltype.Struct): + for name in TYPE._names: + FIELD = getattr(TYPE, name) + if isinstance(FIELD, lltype.Array): + continue # skip inlined array + baseofs = llmemory.offsetof(TYPE, name) + suboffsets = offsets_to_gc_pointers(FIELD) + for s in suboffsets: + if s == 0: + offsets.append(baseofs) + else: + offsets.append(baseofs + s) + elif (isinstance(TYPE, lltype.Ptr) and TYPE._needsgc() and + TYPE.TO is not lltype.PyObject): + offsets.append(0) + return offsets # ___________________________________________________________________ # calculate some statistics about the number of variables that need Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Fri Mar 3 16:31:47 2006 @@ -178,16 +178,23 @@ if i == show_i: dump() show_i += 1000 + work_to_do = False if not is_later_yet: - self.gctransformer.finish() + newgcdependencies = self.gctransformer.finish() + if newgcdependencies: + work_to_do = True + for value in newgcdependencies: + if isinstance(typeOf(value), ContainerType): + self.getcontainernode(value) + else: + self.get(value) is_later_yet = True if self.latercontainerlist: + work_to_do = True for node in self.latercontainerlist: node.make_funcgen() self.containerlist.append(node) self.latercontainerlist = [] - else: - work_to_do = False self.completed = True if show_progress: dump() Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Fri Mar 3 16:31:47 2006 @@ -193,7 +193,8 @@ class TestUsingFramework(AbstractTestClass): from pypy.translator.c.gc import FrameworkGcPolicy as gcpolicy - def test_nongcing_gc(self): + def test_framework_simple(self): + py.test.skip("in progress, getting there :-)") def g(x): return x + 1 class A(object): From auc at codespeak.net Fri Mar 3 18:36:53 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 3 Mar 2006 18:36:53 +0100 (CET) Subject: [pypy-svn] r23954 - pypy/dist/pypy/lib/logic Message-ID: <20060303173653.B1D09100BC@code0.codespeak.net> Author: auc Date: Fri Mar 3 18:36:51 2006 New Revision: 23954 Modified: pypy/dist/pypy/lib/logic/oz-dataflow-concurrency.txt Log: some words about futures Modified: pypy/dist/pypy/lib/logic/oz-dataflow-concurrency.txt ============================================================================== --- pypy/dist/pypy/lib/logic/oz-dataflow-concurrency.txt (original) +++ pypy/dist/pypy/lib/logic/oz-dataflow-concurrency.txt Fri Mar 3 18:36:51 2006 @@ -1,15 +1,18 @@ -Some rough notes about the Oz threading model -============================================= +==================================================================== +Some rough notes about the Oz threading model and dataflow variables +==================================================================== (almost verbatim from CTM) +Threads +======= + Scheduling ---------- Fair scheduling through round-robin. -Needs not be deterministic (would be nice, especially when debugging, -but probably impossible to achieve). +Needs not be deterministic. With priority levels : three queues exist, which manage high, medium, low priority threads. The time slice ratio for these is @@ -77,9 +80,9 @@ The combination of threads and dataflow variables leads to implicit synchronization : that means synchronization is not textually visible -in the source code but follow from the semantics of dataflow variables -; using such a variable implies synchronization on the variable being -bound to a value. +in the source code but follow from the semantics of dataflow +variables; using such a variable implies synchronization on the +variable being bound to a value. Eager execution (the mere fact of executing statements as they present themselves to the interpreter, withou delay) plus dataflow vars also @@ -94,7 +97,7 @@ values can be seen as complete values that are only partially known"). Dataflow variables ------------------- +================== (see http://www.sics.se/~frej/flow_java/ for an implementation of dataflow variables in Java). @@ -121,3 +124,57 @@ values, provided the partial values are compatible (unifiable) with each other. +Futures +======= + +Dataflow variables are but one technique to implement dataflow +execution. Another, quite popular technique is based on a slightly +different concept, the single-assignment variable. Two of the +best-known instances of the single-assignment variable are futures and +I-structures. The purpose of futures and I-structures is to increase +the potential parallelism of a program by removing inessential +dependencies between calculations. They allow concurrency between a +computation that calculates a value and one that uses the value. This +concurrency can be exploited on a parallel machine. We define futures +and I-structures and compare them with dataflow variables. + +Futures were first introduced in Multilisp, a language intended for +writting parallel programs. Multilisp introduces the function call +(future E) where E is any expression. This does two things: it +immediately returns a placeholder for the result of E and it initiates +a concurrent evaluation of E. When the value of E is needed, i.e., a +computation tries to access the placeholder, then the computation +blocks until the value is available. We model this as follows in the +declarative concurrent model (where E is a zero-argument function) : + +fun {Future E} +X in + thread X={E} end + !!X +end + +A future can only be bound by the concurrent computation that is +created along with it. This is enforced by returning a read-only +variable. Multilisp also has a delay construct that does not initiate +any evaluation but uses by-need execution. It causes evaluation of its +argument only when the result is needed. An I-structure (for +"incomplete structure") is an array of single-assignment +variables. Individual elements can be accessed before the elements are +computed. I-structures were introduced as a language construct for +writing parallel programs in dataflow machines, e.g., in the dataflow +language Id. I-structures are also used in pH ("parallel Haskell"), a +recent language design that extends Haskell for implicit +parallelism. An I-structure permits concurrency between a computation +that calculates the array elements and a computation that uses their +values. When the value of an element is needed, then the computatio +blocks until it is available. Like a future and a read-only variable, +an element of an I-structure can only be bound by the computation that +calculates it. There is a fundamental difference between dataflow +variables on one side and futures and I-structures on the other +side. The latter can be bound only once, whereas dataflow variables +can be bound more than once, as long as the bindings are consistent +with each other. Two partial values are consistent if they are +unifiable. A dataflow variable can be bound many times to different +partial values as long as the partial values are unifiable. + + From auc at codespeak.net Fri Mar 3 18:37:56 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 3 Mar 2006 18:37:56 +0100 (CET) Subject: [pypy-svn] r23955 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060303173756.47B2B100BC@code0.codespeak.net> Author: auc Date: Fri Mar 3 18:37:53 2006 New Revision: 23955 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: end of simple var update notes about futures Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Fri Mar 3 18:37:53 2006 @@ -1,11 +1,28 @@ # TODO -# * support several distribution strategies -# * add a linear constraint solver (vital for fast +# * [1] adapt other distribution strategies +# * [5] add a linear constraint solver (vital for fast # constraint propagation over finite integer domains) # and other kinds of specialized propagators -# * make all propagators live in their own threads and +# * [9] make all propagators live in their own threads and # be awakened by variable/domains events + +# Gert Smolka in +# http://www.cetic.be/moz2004/talks/MOZ2004.pdf : +# * Abandon Logic Variables +# * can be bound everywhere +# * malicious consummer can bind tail variable of stream +# * break abstractions +# * unification not needed +# * Have Futures instead +# * Multilisp [Halstead 85] +# * added to Mozart in 1998 +# * refine logic variable into +# * consummer end (future) +# * producer end (promise) +# * dataflow synchronization + by-need synchronization + + from threading import Thread, Condition, RLock, local from state import Succeeded, Distributable, Failed, \ @@ -123,10 +140,10 @@ def _init_choose_commit(self): # create a unique choice point - # using two vars as channels betwen + # using two spaceless vars as channels betwen # space and distributor threads - self.CHOOSE = self._make_choice_var() - self.STABLE = self._make_stable_var() + self.CHOOSE = SimpleVar() + self.STABLE = SimpleVar() #-- utilities & instrumentation ----------------------------- @@ -196,13 +213,6 @@ #-- space helpers ----------------------------------------- - def _make_choice_var(self): - return SimpleVar() - - def _make_stable_var(self): - return SimpleVar() - - def _process(self): """wraps the propagator""" if len(self.event_set): @@ -266,7 +276,7 @@ """ # did you ask before ... ? assert self.STABLE.is_bound() - self.STABLE = self._make_stable_var() + self.STABLE = SimpleVar() self.CHOOSE.bind(choice) def choose(self, nb_choices): Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Fri Mar 3 18:37:53 2006 @@ -2,6 +2,7 @@ from threading import Thread from state import Succeeded, Distributable, Failed, Forsaken from event import Revise +from variable import SimpleVar def arrange_domains(cs, variables): """build a data structure from var to dom @@ -153,7 +154,7 @@ print "-- distribution & propagation (%s) --" % self.cs.id self.distribute(choice-1) self.cs._process() - self.cs.CHOOSE = self.cs._make_choice_var() + self.cs.CHOOSE = SimpleVar() self.cs.STABLE.bind(True) # unlocks Ask print "-- distributor terminated (%s) --" % self.cs.id Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Fri Mar 3 18:37:53 2006 @@ -486,6 +486,8 @@ # we need to carefully craft some noop problems # for these tests +# also what is tested below is tested in other places +# so me might want to just forget about it ## def test_ask_success(self): ## spc = newspace(problems.one_solution_problem) From nik at codespeak.net Sat Mar 4 11:05:59 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Sat, 4 Mar 2006 11:05:59 +0100 (CET) Subject: [pypy-svn] r23970 - in pypy/dist/pypy: interpreter/pyparser rpython rpython/lltypesystem Message-ID: <20060304100559.98961100C6@code0.codespeak.net> Author: nik Date: Sat Mar 4 11:05:56 2006 New Revision: 23970 Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py pypy/dist/pypy/rpython/lltypesystem/rpbc.py pypy/dist/pypy/rpython/rpbc.py Log: fix an annotation problem in the parser. add an import lost in some ootype refactoring. this makes translation work again for me. Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/pythonparse.py (original) +++ pypy/dist/pypy/interpreter/pyparser/pythonparse.py Sat Mar 4 11:05:56 2006 @@ -172,7 +172,10 @@ def grammar_rules( space ): - return space.wrap( PYTHON_PARSER.rules ) + w_rules = space.newdict([]) + for key, value in PYTHON_PARSER.rules.iteritems(): + space.setitem(w_rules, space.wrap(key), space.wrap(value)) + return w_rules def make_rule( space, w_rule ): Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rpbc.py Sat Mar 4 11:05:56 2006 @@ -7,7 +7,6 @@ typeOf, Void, ForwardReference, Struct, Bool, \ Ptr, malloc, nullptr from pypy.rpython.rmodel import Repr, TyperError, inputconst, inputdesc -from pypy.rpython.rmodel import warning, mangle, CanBeNull from pypy.rpython import robject from pypy.rpython import rtuple from pypy.rpython.rpbc import samesig,\ Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Sat Mar 4 11:05:56 2006 @@ -8,7 +8,7 @@ typeOf, Void, Bool, nullptr, frozendict, Ptr, Struct, malloc from pypy.rpython.error import TyperError from pypy.rpython.rmodel import Repr, inputconst, HalfConcreteWrapper, CanBeNull, \ - mangle, inputdesc + mangle, inputdesc, warning from pypy.rpython import rclass from pypy.rpython import robject From tismer at codespeak.net Mon Mar 6 01:33:54 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 6 Mar 2006 01:33:54 +0100 (CET) Subject: [pypy-svn] r23995 - in pypy/dist/pypy/translator/c/winproj: extension standalone Message-ID: <20060306003354.0924E100B9@code0.codespeak.net> Author: tismer Date: Mon Mar 6 01:33:33 2006 New Revision: 23995 Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj pypy/dist/pypy/translator/c/winproj/standalone/standalone.vcproj Log: some corrections to the winnows projects. Note that these don't intend to be final and general, but templates to easier get going. Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Mon Mar 6 01:33:33 2006 @@ -33,6 +33,7 @@ Name="VCCustomBuildTool"/> @@ -78,7 +80,8 @@ Name="VCCustomBuildTool"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\common_header.h"> + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\testing_1.c"> Modified: pypy/dist/pypy/translator/c/winproj/standalone/standalone.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/standalone/standalone.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/standalone/standalone.vcproj Mon Mar 6 01:33:33 2006 @@ -208,181 +208,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\testing_1.c"> From tismer at codespeak.net Mon Mar 6 02:29:00 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 6 Mar 2006 02:29:00 +0100 (CET) Subject: [pypy-svn] r24001 - pypy/dist/pypy/translator Message-ID: <20060306012900.F128E100B9@code0.codespeak.net> Author: tismer Date: Mon Mar 6 02:28:57 2006 New Revision: 24001 Modified: pypy/dist/pypy/translator/translator.py Log: docstring did not represent reality -> translatorshell - XXX is there any way to at least detect such things automatically? Modified: pypy/dist/pypy/translator/translator.py ============================================================================== --- pypy/dist/pypy/translator/translator.py (original) +++ pypy/dist/pypy/translator/translator.py Mon Mar 6 02:28:57 2006 @@ -2,7 +2,7 @@ The Translator is a glue class putting together the various pieces of the translation-related code. It can be used for interactive testing of the -translator; see pypy/bin/translator.py. +translator; see pypy/bin/translatorshell.py. """ import autopath, os, sys, types, copy From tismer at codespeak.net Mon Mar 6 03:03:25 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 6 Mar 2006 03:03:25 +0100 (CET) Subject: [pypy-svn] r24005 - pypy/dist/pypy/translator/tool Message-ID: <20060306020325.67432100AB@code0.codespeak.net> Author: tismer Date: Mon Mar 6 03:03:22 2006 New Revision: 24005 Modified: pypy/dist/pypy/translator/tool/cbuild.py Log: enable generation of debug info for win32. This is way more convenient than to have to recompile. No idea if this can influence program speed, but I don't care since CPython doesn't neither. Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Mon Mar 6 03:03:22 2006 @@ -94,7 +94,8 @@ extra_compile_args = [] # ensure correct math on windows if sys.platform == 'win32': - extra_compile_args.append('/Op') + extra_compile_args.append('/Op') # get extra precision + extra_compile_args.append('/PDB:laber') # create debug info if get_default_compiler() == 'unix': old_version = False try: @@ -273,6 +274,8 @@ self.libraries.append('pthread') self.compile_extra += ['-O2', '-pthread'] self.link_extra += ['-pthread'] + if sys.platform == 'win32': + self.link_extra += ['/DEBUG'] # generate .pdb file if sys.platform == 'darwin': if '/sw/include' not in self.include_dirs: self.include_dirs.append('/sw/include') From mwh at codespeak.net Mon Mar 6 11:21:59 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 6 Mar 2006 11:21:59 +0100 (CET) Subject: [pypy-svn] r24007 - pypy/dist/pypy/translator/c Message-ID: <20060306102159.409611009F@code0.codespeak.net> Author: mwh Date: Mon Mar 6 11:21:57 2006 New Revision: 24007 Modified: pypy/dist/pypy/translator/c/funcgen.py Log: improve an exception message very slightly Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Mon Mar 6 11:21:57 2006 @@ -425,7 +425,8 @@ try: cleanup = op.cleanup except AttributeError: - raise AttributeError("(in)direct_call %r without explicit .cleanup" % op) + raise AttributeError("%r without explicit .cleanup" + % (op,)) if cleanup is not None: # insert the 'finally' operations before the exception check cleanup_finally, cleanup_except = op.cleanup From nico at codespeak.net Mon Mar 6 16:46:34 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Mon, 6 Mar 2006 16:46:34 +0100 (CET) Subject: [pypy-svn] r24023 - pypy/dist/pypy/doc Message-ID: <20060306154634.A77AC100CA@code0.codespeak.net> Author: nico Date: Mon Mar 6 16:46:32 2006 New Revision: 24023 Modified: pypy/dist/pypy/doc/events.txt pypy/dist/pypy/doc/news.txt Log: pycon is over. logic sprint starts. Modified: pypy/dist/pypy/doc/events.txt ============================================================================== --- pypy/dist/pypy/doc/events.txt (original) +++ pypy/dist/pypy/doc/events.txt Mon Mar 6 16:46:32 2006 @@ -7,26 +7,6 @@ .. _`over there`: webcal://pypycal.sabi.net///calendars/PyPy.ics -Talks at PyCon 2006 (Dallas, Texas, USA) -=================================================================== - -*Feb 24th - Feb 26th 2006.* PyPy developers will speak at `PyCon 2006`_. - -.. _`PyCon 2006`: http://us.pycon.org/TX2006/HomePage - -PyCon Sprint 2006 (Dallas, Texas, USA) -================================================================== - -*Feb 27th - March 2nd 2006.* The Post-PyCon PyPy Sprint is scheduled to -take place right after PyCon 2006. - -We hope to see lots of newcomers at this sprint, so we'll give -friendly introductions. Note that during the Pycon conference we are -giving PyPy talks which serve well as preparation. Read more in the -`announcement`_. - -.. _`announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/pycon06/sprint-announcement.html - Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) ======================================================================== Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Mon Mar 6 16:46:32 2006 @@ -7,6 +7,23 @@ .. _Python: http://www.python.org/doc/current/ref/ref.html .. _`more...`: http://codespeak.net/pypy/dist/pypy/doc/architecture.html#mission-statement +PyCon Sprint 2006 (Dallas, Texas, USA) +================================================================== + +*Feb 27th - March 2nd 2006.* The Post-PyCon PyPy Sprint took place +right after PyCon 2006. + +A report is coming up. + + +Talks at PyCon 2006 (Dallas, Texas, USA) +=================================================================== + +*Feb 24th - Feb 26th 2006.* PyPy developers spoke at `PyCon 2006`_. + +.. _`PyCon 2006`: http://us.pycon.org/TX2006/HomePage + + PyPy at Solutions Linux in Paris January 31st - February 2nd 2006 =================================================================== From mwh at codespeak.net Mon Mar 6 16:51:10 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 6 Mar 2006 16:51:10 +0100 (CET) Subject: [pypy-svn] r24024 - in pypy/dist/pypy: rpython/memory translator/c translator/c/test Message-ID: <20060306155110.5353E100C9@code0.codespeak.net> Author: mwh Date: Mon Mar 6 16:51:08 2006 New Revision: 24024 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/gc.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: Make the first gc framework using test run. Woohoo! Bits I remember: - fixed a bug in StackRootIterator - make sure FrameworkGCTransformer.gcdata.type_info_table doesn't get annotated as a constant - replace FrameworkGCTransformer.gcdata.type_info_table at the llpython, not the rpython level - make sure all types in the graph get typeids - pass the gc object to malloc - make genc emit the fields that the gc needs Open issues: - it's rather hard-coded to MarkSweepGC - some general ugliness - there's no way to be sure that the test actually triggered a collection yet! Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Mon Mar 6 16:51:08 2006 @@ -688,9 +688,8 @@ def pop(self): while self.current != gcdata.root_stack_base: self.current -= sizeofaddr - result = self.current.address[0] - if result != NULL: - return result + if self.current.address[0] != NULL: + return self.current return NULL def frameworkgc_setup(): @@ -719,6 +718,15 @@ gcdata.root_stack_top = top return result + bk = self.translator.annotator.bookkeeper + + # the point of this little dance is to not annotate + # self.gcdata.type_info_table as a constant. + data_classdef = bk.getuniqueclassdef(GCData) + data_classdef.generalize_attr( + 'type_info_table', + annmodel.SomePtr(lltype.Ptr(GCData.TYPE_INFO_TABLE))) + annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) frameworkgc_setup_graph = annhelper.getgraph(frameworkgc_setup, [], annmodel.s_None) @@ -727,7 +735,7 @@ annmodel.s_None) pop_root_graph = annhelper.getgraph(pop_root, [], annmodel.SomeAddress()) - bk = self.translator.annotator.bookkeeper + classdef = bk.getuniqueclassdef(GCData.GCClass) s_gcdata = annmodel.SomeInstance(classdef) malloc_graph = annhelper.getgraph(GCData.GCClass.malloc.im_func, @@ -740,7 +748,7 @@ attach_empty_cleanup=True) self.push_root_ptr = self.graph2funcptr(push_root_graph) self.pop_root_ptr = self.graph2funcptr(pop_root_graph) - self.malloc_ptr = self.graph2funcptr(malloc_graph) + self.malloc_ptr = self.graph2funcptr(malloc_graph, True) def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True @@ -796,6 +804,18 @@ def finish(self): newgcdependencies = super(FrameworkGCTransformer, self).finish() if self.type_info_list is not None: + # XXX this is a kind of sledgehammer-wallnut approach to make sure + # all types get an ID. + for graph in self.translator.graphs: + for block in graph.iterblocks(): + for v in block.getvariables() + block.getconstants(): + t = getattr(v, 'concretetype', None) + if t is None: + continue + if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \ + t._needsgc(): + self.get_type_id(v.concretetype.TO) + table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) for tableentry, newcontent in zip(table, self.type_info_list): @@ -803,12 +823,24 @@ setattr(tableentry, key, value) self.type_info_list = None self.offsettable_cache = None + # replace the type_info_table pointer in gcdata -- at this point, # the database is in principle complete, so it has already seen # the old (empty) array. We need to force it to consider the new # array now. It's a bit hackish as the old empty array will also # be generated in the C source, but that's a rather minor problem. - self.gcdata.type_info_table = table + + # XXX because we call inputconst already in replace_malloc, we can't + # modify the instance, we have to modify the 'rtyped instance' + # instead. horrors. is there a better way? + + s_gcdata = self.translator.annotator.bookkeeper.immutablevalue( + self.gcdata) + r_gcdata = self.translator.rtyper.getrepr(s_gcdata) + ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value + ll_instance.inst_type_info_table = table + #self.gcdata.type_info_table = table + newgcdependencies = newgcdependencies or [] newgcdependencies.append(table) return newgcdependencies @@ -834,10 +866,22 @@ v_length = rmodel.inputconst(lltype.Signed, 0) else: v_length = op.args[1] + + # surely there's a better way of doing this? + s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(self.gcdata) + r_gcdata = self.translator.rtyper.getrepr(s_gcdata) + s_gc = self.translator.annotator.bookkeeper.valueoftype(self.gcdata.GCClass) + r_gc = self.translator.rtyper.getrepr(s_gc) + + newop0 = SpaceOperation( + "getfield", + [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc")], + varoftype(r_gc.lowleveltype)) newop = SpaceOperation("direct_call", - [self.malloc_ptr, c_type_id, v_length], + [self.malloc_ptr, newop0.result, c_type_id, v_length], v) ops, finally_ops = self.protect_roots(newop, livevars) + ops.insert(0, newop0) ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result)) return ops, finally_ops, 1 Modified: pypy/dist/pypy/translator/c/gc.py ============================================================================== --- pypy/dist/pypy/translator/c/gc.py (original) +++ pypy/dist/pypy/translator/c/gc.py Mon Mar 6 16:51:08 2006 @@ -283,3 +283,10 @@ def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op, err): args = [funcgen.expr(v) for v in op.args] return '%s = %s; /* for moving GCs */' % (args[1], args[0]) + + def common_gcheader_definition(self, defnode): + return [('flags', lltype.Signed), ('typeid', lltype.Signed)] + + def common_gcheader_initdata(self, defnode): + # this more or less assumes mark-and-sweep gc + return [0, defnode.db.gctransformer.id_of_type[defnode.T]] Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Mon Mar 6 16:51:08 2006 @@ -194,7 +194,6 @@ from pypy.translator.c.gc import FrameworkGcPolicy as gcpolicy def test_framework_simple(self): - py.test.skip("in progress, getting there :-)") def g(x): return x + 1 class A(object): @@ -202,6 +201,10 @@ def f(): a = A() a.b = g(1) + # this should trigger a couple of collections + # XXX make sure it triggers at least one somehow! + for i in range(100000): + [A()] * 1000 return a.b fn = self.getcompiled(f) res = fn() From nik at codespeak.net Mon Mar 6 16:56:45 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 6 Mar 2006 16:56:45 +0100 (CET) Subject: [pypy-svn] r24025 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060306155645.7E634100A3@code0.codespeak.net> Author: nik Date: Mon Mar 6 16:56:44 2006 New Revision: 24025 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: devised some hackish way to have code generated by GenSqueak actually run on a squeak vm. got a very basic test passing. need to think a lot now about how to proceed. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Mon Mar 6 16:56:44 2006 @@ -95,6 +95,7 @@ self.pendingmethods = [] self.classes = [] self.methods = [] + self.function_container = False t = self.translator graph = t.graphs[0] @@ -106,7 +107,8 @@ self.translator.view() self.nameof(graph) #add to pending - file = self.sqdir.join('%s.st' % graph.name).open('w') + self.filename = '%s.st' % graph.name + file = self.sqdir.join(self.filename).open('w') self.gen_source(file) file.close() @@ -240,16 +242,29 @@ yield " %s" % line yield "]" + if not self.function_container: + self.gen_function_container(f) + self.function_container = True + start = graph.startblock args = [expr(arg) for arg in start.inputargs] + print >> f, "!PyFunctions class methodsFor: 'functions'" \ + " stamp: 'pypy 1/1/2000 00:00'!" print >> f, '%s' % signature(self.nameof(graph), args) - + loops = LoopFinder(start).loops for line in render_block(start): print >> f, ' %s' % line print >> f + def gen_function_container(self, f): + print >> f, """Object subclass: #PyFunctions + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'PyPy'!""" + def nameof(self, obj): key = Constant(obj).key try: Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Mon Mar 6 16:56:44 2006 @@ -1,3 +1,5 @@ +import os +import py from pypy.tool.udir import udir from pypy.translator.test import snippet from pypy.translator.squeak.gensqueak import GenSqueak @@ -10,27 +12,80 @@ while j > 0: j -= 1 -class TestSqueakTrans: +def build_sqfunc(func): + try: func = func.im_func + except AttributeError: pass + t = TranslationContext() + graph = t.buildflowgraph(func) + t._prebuilt_graphs[func] = graph + gen = GenSqueak(udir, t) + return gen - def build_sqfunc(self, func): - try: func = func.im_func - except AttributeError: pass - t = TranslationContext() - graph = t.buildflowgraph(func) - t._prebuilt_graphs[func] = graph - self.gen = GenSqueak(udir, t) +class TestSqueakTrans: def test_simple_func(self): - self.build_sqfunc(snippet.simple_func) + build_sqfunc(snippet.simple_func) def test_if_then_else(self): - self.build_sqfunc(snippet.if_then_else) + build_sqfunc(snippet.if_then_else) def test_two_plus_two(self): - self.build_sqfunc(snippet.two_plus_two) + build_sqfunc(snippet.two_plus_two) def test_my_gcd(self): - self.build_sqfunc(snippet.my_gcd) + build_sqfunc(snippet.my_gcd) def test_looping(self): - self.build_sqfunc(looping) + build_sqfunc(looping) + + +# For now use pipes to communicate with squeak. This is very flaky +# and only works for posix systems. At some later point we'll +# probably need a socket based solution for this. +startup_script = """ +| stdout src function result | +src := Smalltalk getSystemAttribute: 3. +FileStream fileIn: src. +function := Smalltalk getSystemAttribute: 4. +result := Compiler new evaluate: ('PyFunctions ' , function) in: nil to: nil. +stdout := StandardFileStream fileNamed: '/dev/stdout'. +stdout nextPutAll: result asString. +Smalltalk snapshot: false andQuit: true. +""" + +class TestGenSqueak: + + def setup_class(self): + self.startup_st = udir.join("startup.st") + f = self.startup_st.open("w") + f.write(startup_script) + f.close() + + def run_on_squeak(self, function): + try: + import posix + except ImportError: + py.skip("Squeak tests only work on Unix right now.") + try: + py.path.local.sysfind("squeak") + except py.error.ENOENT: + py.skip("Squeak is not on your path.") + if os.getenv("SQUEAK_IMAGE") is None: + py.skip("Squeak tests expect the SQUEAK_IMAGE environment " + "variable to point to an image.") + gen_squeak = build_sqfunc(function) + squeak_process = os.popen("squeak -headless -- %s %s %s" + % (self.startup_st, udir.join(gen_squeak.filename), + # HACK XXX. Only works for functions without arguments. + # Need to really rethink how selectors are assigned + # to functions. + function.__name__)) + result = squeak_process.read() + assert squeak_process.close() is None # exit status was 0 + return result + + def test_theanswer(self): + def theanswer(): + return 42 + assert self.run_on_squeak(theanswer) == "42" + From ale at codespeak.net Mon Mar 6 17:14:48 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Mon, 6 Mar 2006 17:14:48 +0100 (CET) Subject: [pypy-svn] r24026 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060306161448.BEA0A100CB@code0.codespeak.net> Author: ale Date: Mon Mar 6 17:14:47 2006 New Revision: 24026 Modified: pypy/dist/pypy/lib/logic/computation_space/problems.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: (George Paci, ale) A not finished Sudoku solver, and a not working test Modified: pypy/dist/pypy/lib/logic/computation_space/problems.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/problems.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/problems.py Mon Mar 6 17:14:47 2006 @@ -114,4 +114,35 @@ for conf2 in variables: if conf2 > conf1: cs.add_constraint([conf1,conf2], '%s != %s'%(conf1.name,conf2.name)) + return tuple(variables) + +def sudoku(computation_space): + cs = computation_space + import constraint as c + + variables = [cs.var('v%i%i'%(x,y)) for x in range(1,10) for y in range(1,10)] + + # Make the variables + for v in variables: + cs.set_dom(v, c.FiniteDomain(range(1,10))) + # Add constraints for rows (sum should be 45) + for i in range(1,10): + row = [ v for v in variables if v.name[1] == str(i)] + cs.add_constraint(row, 'sum([%s]) == 45' % ', '.join([v.name for v in row])) + # Add constraints for columns (sum should be 45) + for i in range(1,10): + row = [ v for v in variables if v.name[2] == str(i)] + cs.add_constraint(row, 'sum([%s]) == 45' % ', '.join([v.name for v in row])) + # Add constraints for subsquares (sum should be 45) + offsets = [(r,c) for r in [-1,0,1] for c in [-1,0,1]] + subsquares = [(r,c) for r in [2,5,8] for c in [2,5,8]] + for rc in subsquares: + sub = [cs.get_var_by_name('v%d%d'% (rc[0] + off[0],rc[1] + off[1])) for off in offsets] + cs.add_constraint(sub, 'sum([%s]) == 45' % ', '.join([v.name for v in sub])) + for v in sub: + for m in sub[sub.index(v)+1:]: + cs.add_constraint([v,m], '%s != %s' % (v.name, m.name)) + #print cs.constraints + return tuple(variables) + Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Mon Mar 6 17:14:47 2006 @@ -596,4 +596,38 @@ assert len(sols) == 64 print sols + def no_test_sudoku(self): + #spc = newspace(problems.sudoku) + #print spc.constraints + def more_constraints(space): + f = 'puzzle1.su' + + file = open(f) + c = [] + row = 1 + for line in file.readlines(): + for col in range(1,10): + if line[col-1] != ' ': + tup = ('v%d%d' % (col, row), int(line[col-1])) + space.add_constraint([space.get_var_by_name(tup[0])],'%s == %d' % tup) + row += 1 + + #nspc = spc.clone() + #nspc.inject(more_constraints) + #print nspc.constraints + sol2 = strategies.dfs_one(strategies.sudoku) + print "done dfs" + #sol2 = [var.val for var in sol] + assert sol2 == [('room A', 'day 1 PM'), + ('room B', 'day 2 PM'), + ('room C', 'day 2 AM'), + ('room C', 'day 2 PM'), + ('room C', 'day 1 AM'), + ('room C', 'day 1 PM'), + ('room A', 'day 2 PM'), + ('room B', 'day 1 AM'), + ('room A', 'day 2 AM'), + ('room A', 'day 1 AM')] + + From ale at codespeak.net Mon Mar 6 17:31:15 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Mon, 6 Mar 2006 17:31:15 +0100 (CET) Subject: [pypy-svn] r24027 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060306163115.05046100C6@code0.codespeak.net> Author: ale Date: Mon Mar 6 17:31:14 2006 New Revision: 24027 Added: pypy/dist/pypy/lib/logic/computation_space/parsesudoku.py pypy/dist/pypy/lib/logic/computation_space/puzzle1.su pypy/dist/pypy/lib/logic/computation_space/solution.su Log: (George Paci, ale) I forgot these a sudoku puzle and a solution and a parser for the puzzles Added: pypy/dist/pypy/lib/logic/computation_space/parsesudoku.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/computation_space/parsesudoku.py Mon Mar 6 17:31:14 2006 @@ -0,0 +1,11 @@ +import sys + +file = open(sys.argv[1]) +c = [] +row = 1 +for line in file.readlines(): + for col in range(1,10): + if line[col-1] != ' ': + c.append(('v%d%d' % (col, row), int(line[col-1]))) +print c + Added: pypy/dist/pypy/lib/logic/computation_space/puzzle1.su ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/computation_space/puzzle1.su Mon Mar 6 17:31:14 2006 @@ -0,0 +1,9 @@ + 74 65 +5 6 7 3 +3 9 2 1 + 2 413 8 + 8 5 + 5 276 1 +4 7 1 2 +6 7 1 5 + 15 49 Added: pypy/dist/pypy/lib/logic/computation_space/solution.su ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/computation_space/solution.su Mon Mar 6 17:31:14 2006 @@ -0,0 +1,9 @@ +274139658 +581627943 +369584271 +726413589 +143895726 +958276314 +437958162 +692741835 +815362497 From mwh at codespeak.net Mon Mar 6 18:00:01 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 6 Mar 2006 18:00:01 +0100 (CET) Subject: [pypy-svn] r24028 - pypy/dist/pypy/translator/c/test Message-ID: <20060306170001.9E763100C4@code0.codespeak.net> Author: mwh Date: Mon Mar 6 18:00:00 2006 New Revision: 24028 Modified: pypy/dist/pypy/translator/c/test/test_newgc.py Log: a skipped, failing test Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Mon Mar 6 18:00:00 2006 @@ -209,3 +209,22 @@ fn = self.getcompiled(f) res = fn() assert res == 2 + + def test_framework_static_routes(self): + py.test.skip("not working yet") + class A(object): + pass + static_list = [] + N = 100000 + def f(): + for i in range(100000): + a = A() + a.x = i + static_list.append(a) + r = 0 + for a in static_list: + r += a.x + return r + fn = self.getcompiled(f) + res = fn() + assert res == 100000*(100000 - 1)/2 From cfbolz at codespeak.net Tue Mar 7 09:43:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 09:43:03 +0100 (CET) Subject: [pypy-svn] r24036 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307084303.DF6191009D@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 09:42:50 2006 New Revision: 24036 Added: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Log: (all) some rough planning from yesterday Added: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Tue Mar 7 09:42:50 2006 @@ -0,0 +1,24 @@ +Louvain-la-Neuve Logic programming sprint +========================================= + +Tasks: +------ + + * identify parts of the current logic module that can be usefully implemented + in RPython + * take a look at existion logic programming software (pychinko, + GECODE, CWM, tableau, pylog) and at the RETE algorithm think about + integration with + * existing Python syntax/new syntax: look at and update document desicribing + * some of the ideas consistency for multi-paradigm programming languages in + Python especially + + +Links: +------ + + * description of the Rete algorithm: http://drools.org/Rete + * CWM (closed world machine): http://infomesh.net/2001/cwm/ + * pychinko: http://www.mindswap.org/~katz/pychinko/ + * pylog (implementation of prolog in python): http://christophe.delord.free.fr/en/pylog/ + * cookbook receipt that lets one add arbitrary infix binary operators: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 From cfbolz at codespeak.net Tue Mar 7 10:00:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 10:00:00 +0100 (CET) Subject: [pypy-svn] r24037 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307090000.C68DF100AB@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 09:59:59 2006 New Revision: 24037 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Log: assigning of pairs Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Tue Mar 7 09:59:59 2006 @@ -4,14 +4,14 @@ Tasks: ------ + * plan the agenda for tomorrow/thursday (Aurelien, Nicolas) * identify parts of the current logic module that can be usefully implemented - in RPython - * take a look at existion logic programming software (pychinko, - GECODE, CWM, tableau, pylog) and at the RETE algorithm think about - integration with + in RPython (Ludovic, Samuele) + * take a look at existing logic programming software (pychinko, + GECODE, CWM, tableau, pylog) and at the RETE algorithm. Think about + integration (Alf, Carl Friedrich, Anders) * existing Python syntax/new syntax: look at and update document desicribing - * some of the ideas consistency for multi-paradigm programming languages in - Python especially + * consistency for multi-paradigm programming languages (especially Python) Links: From cfbolz at codespeak.net Tue Mar 7 10:29:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 10:29:10 +0100 (CET) Subject: [pypy-svn] r24039 - pypy/extradoc/talk/22c3 Message-ID: <20060307092910.5617E10092@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 10:29:05 2006 New Revision: 24039 Added: pypy/extradoc/talk/22c3/hpk-tech.pdf pypy/extradoc/talk/22c3/hpk-tech.rst2pdfconfig pypy/extradoc/talk/22c3/py-web.png - copied unchanged from r24006, pypy/eu-tracking/deliverable/img/py-web.png Log: add a pdf version of the ccc tech talk Added: pypy/extradoc/talk/22c3/hpk-tech.pdf ============================================================================== Files (empty file) and pypy/extradoc/talk/22c3/hpk-tech.pdf Tue Mar 7 10:29:05 2006 differ Added: pypy/extradoc/talk/22c3/hpk-tech.rst2pdfconfig ============================================================================== --- (empty file) +++ pypy/extradoc/talk/22c3/hpk-tech.rst2pdfconfig Tue Mar 7 10:29:05 2006 @@ -0,0 +1,14 @@ +rest_sources = [ + 'hpk-tech.txt', +] + +rest_options = ['--use-latex-footnotes', '--use-latex-toc'] +toc_depth = 2 + +logo = 'py-web.png' +heading = 'PyPy - The New Python Implementation on the Block' +# pagebreak = True +# possible fonts: +# times, helvetica, new century schoolbock, avant garde, palatino + +font = 'avant garde' From cfbolz at codespeak.net Tue Mar 7 10:33:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 10:33:10 +0100 (CET) Subject: [pypy-svn] r24040 - pypy/extradoc/talk/22c3 Message-ID: <20060307093310.87E7A100AB@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 10:33:09 2006 New Revision: 24040 Added: pypy/extradoc/talk/22c3/agility_v1.txt - copied unchanged from r24006, pypy/extradoc/talk/22c3/agility_v1.txt.txt Removed: pypy/extradoc/talk/22c3/agility_v1.txt.txt Log: finally remove the strange additionally .txt From cfbolz at codespeak.net Tue Mar 7 11:35:07 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 11:35:07 +0100 (CET) Subject: [pypy-svn] r24045 - pypy/extradoc/talk/22c3 Message-ID: <20060307103507.F213E100BD@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 11:35:06 2006 New Revision: 24045 Added: pypy/extradoc/talk/22c3/manmoon.png - copied unchanged from r24006, pypy/extradoc/talk/22c3/manmoon.PNG Removed: pypy/extradoc/talk/22c3/manmoon.PNG Log: rename this because latex does not like capital letter endings From cfbolz at codespeak.net Tue Mar 7 11:41:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 11:41:30 +0100 (CET) Subject: [pypy-svn] r24046 - pypy/extradoc/talk/22c3 Message-ID: <20060307104130.7E185100BD@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 11:41:20 2006 New Revision: 24046 Added: pypy/extradoc/talk/22c3/slides-agility.pdf pypy/extradoc/talk/22c3/slides-agility.rst2pdfconfig Log: add pdf for agility talk Added: pypy/extradoc/talk/22c3/slides-agility.pdf ============================================================================== Files (empty file) and pypy/extradoc/talk/22c3/slides-agility.pdf Tue Mar 7 11:41:20 2006 differ Added: pypy/extradoc/talk/22c3/slides-agility.rst2pdfconfig ============================================================================== --- (empty file) +++ pypy/extradoc/talk/22c3/slides-agility.rst2pdfconfig Tue Mar 7 11:41:20 2006 @@ -0,0 +1,14 @@ +rest_sources = [ + 'slides-agility.txt', +] + +rest_options = ['--use-latex-footnotes', '--use-latex-toc'] +toc_depth = 2 + +logo = 'py-web.png' +heading = 'Open Source, EU Funding and Agile Methods' +# pagebreak = True +# possible fonts: +# times, helvetica, new century schoolbock, avant garde, palatino + +font = 'avant garde' From pedronis at codespeak.net Tue Mar 7 12:03:57 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 7 Mar 2006 12:03:57 +0100 (CET) Subject: [pypy-svn] r24047 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060307110357.82910100C9@code0.codespeak.net> Author: pedronis Date: Tue Mar 7 12:03:51 2006 New Revision: 24047 Modified: pypy/dist/pypy/lib/logic/computation_space/constraint.py Log: blank line for readability Modified: pypy/dist/pypy/lib/logic/computation_space/constraint.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/constraint.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/constraint.py Tue Mar 7 12:03:51 2006 @@ -259,6 +259,7 @@ result_cache[var][val] = 1 else: maybe_entailed = 0 + try: for var, keep in result_cache.iteritems(): domain = self.cs.dom(self._names_to_vars[var]) From nico at codespeak.net Tue Mar 7 12:05:41 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Tue, 7 Mar 2006 12:05:41 +0100 (CET) Subject: [pypy-svn] r24048 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307110541.588AA1009D@code0.codespeak.net> Author: nico Date: Tue Mar 7 12:05:40 2006 New Revision: 24048 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Log: proposal of an agenda for tomorrow Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Tue Mar 7 12:05:40 2006 @@ -1,5 +1,5 @@ PyPy/Oz meeting Agenda -====================== +======================= Participants ------------ @@ -23,6 +23,51 @@ * others ? + +Possible Agenda +--------------- + +Presentations + +* goals (nicolas ?) + + Our goal is to add new programming approaches/paradigms to Python and + we would have a lot to learn from your experience with Oz. What + is possible and how far can we go with the current langage + definition? How to enhance Python with logic and keep a + consistent langage? + + understanding of how Oz itself manages the relation between stateful programming and the + declarative parts. + +* PyPy quick description (samuele ?) + +* Adding a constraint store to Python (aurelien ?) + +* Languages integration of Soul (roel) + +Discussions + +* Mozart design philosophy vs. Python design philosophy (peter) + How a little bit of formal semantics can help a lot. The Mozart + philosophy is based on having *two* things at all times: an efficient implementation and a simple + formal semantics. This makes for an interesting balancing act, but the result is worth it I think. + +* Concurrent programming (peter) + lightweight concurrency and support for + asynchronous messages are really very important if you want to "future-proof" Python. Monitors + are terrible; transactions are nice if you can support them in the language. + +* Distributed computing (peter) + A single bullet does not do it justice by a long shot. There are lots + of issues: degree of transparency, language design, distributed algorithms, fault tolerance, openness, security. + +* security features (?) + +* garbage collection (samuele + ?) + + + Topics ------ @@ -32,12 +77,12 @@ Gr?goire: """ - I can think of a few topics for discussion (non exhaustive): -- your ongoing work on implementing a constraint store in pypy +I can think of a few topics for discussion (non exhaustive): +- your ongoing work on implementing a constraint store in pypy - transparent distributed computing - garbage collection - constraint programming: constraint propagation, modeling, search and -computation spaces. + computation spaces. - logic variables and unification - lazy computations - dataflow concurrency (through logic variables or future/promise) @@ -123,13 +168,13 @@ Python, that covers the following : - a constraint store (kind of first-class environment holding up -variables and constraints) which knows how to bind and unify variables, -and how to check satisfiability of constraints -- dataflow variables (with method on them that give (Pyhton) thread -access the wait-til-bound semantics, multiple albeit monotonic binding -of compatible/unifiable values) and streams + variables, domains and constraints) which knows how to bind and unify variables, + and how to propagate constraints on the domains (AC3) +- dataflow variables (with method on them that give (Python, ie OS-threads) thread + access the wait-til-bound semantics, multiple albeit monotonic binding + of compatible/unifiable values) and streams - computation space (embeds/extends a constraint store, provides the -operators defined in CTM) + operators defined in CTM) - sample search strategies & distributors - sample problems exercizing the prototype From ludal at codespeak.net Tue Mar 7 12:13:58 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Tue, 7 Mar 2006 12:13:58 +0100 (CET) Subject: [pypy-svn] r24049 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060307111358.485AB100CA@code0.codespeak.net> Author: ludal Date: Tue Mar 7 12:13:49 2006 New Revision: 24049 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py Log: (auc,pedronis,ludal) join threads after the computation Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Tue Mar 7 12:13:49 2006 @@ -159,7 +159,6 @@ # try to break ref. cycles and help # threads terminate self.status = Forsaken - self.distributor = None self.parent = None self.children = None self.CHOOSE.bind(True) @@ -300,9 +299,11 @@ # var.bind(self.dom(var).get_values()[0]) # shut down the distributor self.CHOOSE.bind(True) + self.status = Forsaken res = [] for var in self.root.val: res.append(self.dom(var).get_values()[0]) + self.distributor.join() return res def set_distributor(self, dist): @@ -386,6 +387,7 @@ def dom(self, var): assert isinstance(var, CsVar) + return self.doms.get(var, NoDom) try: return self.doms[var] except KeyError: Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Tue Mar 7 12:13:49 2006 @@ -146,11 +146,11 @@ #self.cs._process() # propagate first #better let clone() do this call while self.cs._distributable(): + self.cs.STABLE.bind(True) + choice = self.cs.choose(self.nb_subdomains()) if self.cs.status == Forsaken: print "-- distributor (%s) ready for GC --" % self.cs.id break - self.cs.STABLE.bind(True) - choice = self.cs.choose(self.nb_subdomains()) print "-- distribution & propagation (%s) --" % self.cs.id self.distribute(choice-1) self.cs._process() @@ -160,7 +160,6 @@ def distribute(self, choice): - """See AbstractDistributor""" variable = self.findSmallestDomain() #variables = self.cs.get_variables_with_a_domain() #domains = arrange_domains(self.cs, variables) From cfbolz at codespeak.net Tue Mar 7 12:30:16 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 12:30:16 +0100 (CET) Subject: [pypy-svn] r24053 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307113016.EEA4A100A3@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 12:30:14 2006 New Revision: 24053 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Log: add some more links Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Tue Mar 7 12:30:14 2006 @@ -12,7 +12,7 @@ integration (Alf, Carl Friedrich, Anders) * existing Python syntax/new syntax: look at and update document desicribing * consistency for multi-paradigm programming languages (especially Python) - + * write a glossary for terms that occur Links: ------ @@ -22,3 +22,16 @@ * pychinko: http://www.mindswap.org/~katz/pychinko/ * pylog (implementation of prolog in python): http://christophe.delord.free.fr/en/pylog/ * cookbook receipt that lets one add arbitrary infix binary operators: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 + +some more (unsorted) links: + + * http://www.ps.uni-sb.de/~duchier/python/continuations.html + * http://www.jeannot.org/~js/code/index.en.html + * http://candygram.sourceforge.net/ + * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/360698 + * http://lists.logilab.org/pipermail/python-logic/2005-August/000112.html + * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303057 + * http://www.claire-language.com/doc/claire/ + * https://python.taupro.com/repo/Projects/PyIE/trunk/ + * http://www.jeannot.org/~js/code/index.en.html + From ludal at codespeak.net Tue Mar 7 12:59:37 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Tue, 7 Mar 2006 12:59:37 +0100 (CET) Subject: [pypy-svn] r24058 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060307115937.A7699100A3@code0.codespeak.net> Author: ludal Date: Tue Mar 7 12:59:36 2006 New Revision: 24058 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: (ludal,pedronis) remove __hash__ and __eq__ from Variables' class Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Tue Mar 7 12:59:36 2006 @@ -300,9 +300,9 @@ # shut down the distributor self.CHOOSE.bind(True) self.status = Forsaken - res = [] + res = {} for var in self.root.val: - res.append(self.dom(var).get_values()[0]) + res[var.name] = self.dom(var).get_values()[0] self.distributor.join() return res Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Tue Mar 7 12:59:36 2006 @@ -573,22 +573,29 @@ assert new_spc.ask() == space.Succeeded x, y, z = new_spc.find_vars('x', 'y', 'z') res = new_spc.merge() - assert res == [0, 0, 0] + assert res.values() == [0, 0, 0] def test_scheduling_dfs_one_solution(self): sol = strategies.dfs_one(problems.conference_scheduling) - print sol - assert sol == [('room A', 'day 1 PM'), - ('room A', 'day 2 AM'), - ('room C', 'day 2 PM'), - ('room C', 'day 2 AM'), - ('room C', 'day 1 AM'), - ('room C', 'day 1 PM'), - ('room B', 'day 2 AM'), - ('room A', 'day 1 AM'), - ('room B', 'day 2 PM'), - ('room B', 'day 1 AM')] + vars = sol.keys() + vars.sort() + sols = [ sol[k] for k in vars ] + result = [('room A', 'day 1 PM'), + ('room A', 'day 2 AM'), + ('room C', 'day 2 PM'), + ('room C', 'day 2 AM'), + ('room C', 'day 1 AM'), + ('room C', 'day 1 PM'), + ('room B', 'day 2 AM'), + ('room B', 'day 1 AM'), + ('room B', 'day 2 PM'), + ('room A', 'day 1 AM'), + ] + + for v, r1, r2 in zip(vars, sols, result): + print v, r1, r2 + assert sols == result def test_scheduling_all_solutions(self): Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Tue Mar 7 12:59:36 2006 @@ -55,11 +55,6 @@ return self._val val = property(_get_val, _set_val) - def __hash__(self): - return self.name.__hash__() - - def __gt__(self, other): - return self.name.__gt__(other.name) # public interface @@ -140,12 +135,8 @@ def __repr__(self): return self.__str__() - def __eq__(self, thing): - return isinstance(thing, self.__class__) \ - and self.name == thing.name - def bind(self, val): - """top-level space bind""" + """home space bind""" self._cs.bind(self, val) is_bound = _is_bound From mwh at codespeak.net Tue Mar 7 14:31:52 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Mar 2006 14:31:52 +0100 (CET) Subject: [pypy-svn] r24064 - pypy/dist/pypy/translator/c Message-ID: <20060307133152.9FA4610095@code0.codespeak.net> Author: mwh Date: Tue Mar 7 14:31:41 2006 New Revision: 24064 Modified: pypy/dist/pypy/translator/c/node.py Log: don't insert the gc field in reverse order!! Modified: pypy/dist/pypy/translator/c/node.py ============================================================================== --- pypy/dist/pypy/translator/c/node.py (original) +++ pypy/dist/pypy/translator/c/node.py Tue Mar 7 14:31:41 2006 @@ -59,6 +59,9 @@ db = self.db STRUCT = self.STRUCT varlength = self.varlength + if needs_gcheader(self.STRUCT): + for fname, T in db.gcpolicy.struct_gcheader_definition(self): + self.fields.append((fname, db.gettype(T, who_asks=self))) for name in STRUCT._names: T = self.c_struct_field_type(name) if name == STRUCT._arrayfld: @@ -67,9 +70,6 @@ else: typename = db.gettype(T, who_asks=self) self.fields.append((self.c_struct_field_name(name), typename)) - if needs_gcheader(self.STRUCT): - for fname, T in db.gcpolicy.struct_gcheader_definition(self): - self.fields.insert(0, (fname, db.gettype(T, who_asks=self))) self.gcinfo # force it to be computed def computegcinfo(self): From nik at codespeak.net Tue Mar 7 14:31:55 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 7 Mar 2006 14:31:55 +0100 (CET) Subject: [pypy-svn] r24065 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060307133155.1D257100AB@code0.codespeak.net> Author: nik Date: Tue Mar 7 14:31:53 2006 New Revision: 24065 Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: oops. it's py.test.skip not py.skip ... Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Tue Mar 7 14:31:53 2006 @@ -65,13 +65,13 @@ try: import posix except ImportError: - py.skip("Squeak tests only work on Unix right now.") + py.test.skip("Squeak tests only work on Unix right now.") try: py.path.local.sysfind("squeak") except py.error.ENOENT: - py.skip("Squeak is not on your path.") + py.test.skip("Squeak is not on your path.") if os.getenv("SQUEAK_IMAGE") is None: - py.skip("Squeak tests expect the SQUEAK_IMAGE environment " + py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " "variable to point to an image.") gen_squeak = build_sqfunc(function) squeak_process = os.popen("squeak -headless -- %s %s %s" From mwh at codespeak.net Tue Mar 7 14:35:18 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Mar 2006 14:35:18 +0100 (CET) Subject: [pypy-svn] r24066 - pypy/dist/pypy/translator/c/src Message-ID: <20060307133518.7DF9D100A3@code0.codespeak.net> Author: mwh Date: Tue Mar 7 14:35:17 2006 New Revision: 24066 Modified: pypy/dist/pypy/translator/c/src/address.h Log: have raw_malloc use calloc to get zeroed memory, so in particular internal pointers in gcstructs start out life as NULL... argh, this wasted half a day. Modified: pypy/dist/pypy/translator/c/src/address.h ============================================================================== --- pypy/dist/pypy/translator/c/src/address.h (original) +++ pypy/dist/pypy/translator/c/src/address.h Tue Mar 7 14:35:17 2006 @@ -17,7 +17,7 @@ #define OP_ADR_GE(x,y,r,err) r = ((x) >= (y)) #define OP_RAW_MALLOC(size,r,err) \ - r = (void*) malloc(size); \ + r = (void*) calloc(1, size); \ if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ #ifdef MS_WINDOWS From mwh at codespeak.net Tue Mar 7 14:37:30 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Mar 2006 14:37:30 +0100 (CET) Subject: [pypy-svn] r24067 - pypy/dist/pypy/translator/c/test Message-ID: <20060307133730.4A95B100A3@code0.codespeak.net> Author: mwh Date: Tue Mar 7 14:37:25 2006 New Revision: 24067 Modified: pypy/dist/pypy/translator/c/test/test_newgc.py Log: a new test, slightly misleadingly named now i guess, that crashed before my last change to c/src/address.h. Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Tue Mar 7 14:37:25 2006 @@ -210,7 +210,34 @@ res = fn() assert res == 2 - def test_framework_static_routes(self): + def test_framework_varsized(self): + S = lltype.GcStruct("S", ('x', lltype.Signed)) + T = lltype.GcStruct("T", ('y', lltype.Signed), + ('s', lltype.Ptr(S))) + ARRAY_Ts = lltype.GcArray(lltype.Ptr(T)) + + def f(): + r = 0 + for i in range(30): + a = lltype.malloc(ARRAY_Ts, i) + for j in range(i): + a[j] = lltype.malloc(T) + a[j].y = i + a[j].s = lltype.malloc(S) + a[j].s.x = 2*i + r += a[j].y + a[j].s.x + a[j].s = lltype.malloc(S) + a[j].s.x = 3*i + r -= a[j].s.x + for j in range(i): + r += a[j].y + return r + fn = self.getcompiled(f) + res = fn() + assert res == f() + + + def test_framework_static_roots(self): py.test.skip("not working yet") class A(object): pass From ale at codespeak.net Tue Mar 7 14:54:41 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Tue, 7 Mar 2006 14:54:41 +0100 (CET) Subject: [pypy-svn] r24069 - pypy/dist/pypy/lib/logic Message-ID: <20060307135441.C634A100A4@code0.codespeak.net> Author: ale Date: Tue Mar 7 14:54:39 2006 New Revision: 24069 Added: pypy/dist/pypy/lib/logic/use_case_of_logic.txt Log: a file containing areas where logic programming, has or could have a raison d'etre Added: pypy/dist/pypy/lib/logic/use_case_of_logic.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/use_case_of_logic.txt Tue Mar 7 14:54:39 2006 @@ -0,0 +1,70 @@ +Use cases for a combination of Logic and Object Oriaented programming approach +------------------------------------------------------------------------------- + +Workflows +========= + +Defining the next state by solving certain constraints. The more general term +might be State machines. + +Business Logic +============== + +We define Business Logic as expressing consistency (as an example) on a set of +objects in a business application. + +For exeample checking the consistency of a calculation before committing the +changes. + +The domain is quite rich in example of uses of Busines Logic. + +Datamining +=========== + +An example is Genetic sequence matching. + +Databases +========= + +Validity contraints for the data can be expressed as constraints. + +Constraints can be used to perform type inference when querying the database. + +Semantic web +============= + +The use case is like the database case, except the ontology langauge it self is born out of Descriptive Logic + + +User Interfaces +=============== + +We use rules to describe the layout and visibility constraints of elements that +are to be displayed on screen. The rule can also help describing how an element +is to be displayed depending on its state (for instance, out of bound values +can be displayed in a different colour). + +Configuration +============== + +User configuration can use information infered from : the current user, current plantform +, version requirements, ... + +The validity of the configuration can be checked with the constraints. + + +Scheduling and planning +======================== + +Timetables, process scheduling, task scheduling. + +Use rules to determin when to execute tasks (only start batch, if load is low, and previous batch is finished. + +Load sharing. + +Route optimisation. Planning the routes of a technitian based on tools needed and such + +An example is scheduling a confenre like Europython see: + +http://lists.logilab.org/pipermail/python-logic/2005-May/000107.html + From cfbolz at codespeak.net Tue Mar 7 14:57:25 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 14:57:25 +0100 (CET) Subject: [pypy-svn] r24070 - in pypy/dist/pypy: doc/discussion lib/logic Message-ID: <20060307135725.DFD61100A4@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 14:57:19 2006 New Revision: 24070 Added: pypy/dist/pypy/doc/discussion/use_case_of_logic.txt - copied unchanged from r24069, pypy/dist/pypy/lib/logic/use_case_of_logic.txt Removed: pypy/dist/pypy/lib/logic/use_case_of_logic.txt Log: this should really live in discussion From nico at codespeak.net Tue Mar 7 16:20:36 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Tue, 7 Mar 2006 16:20:36 +0100 (CET) Subject: [pypy-svn] r24073 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307152036.62A971008B@code0.codespeak.net> Author: nico Date: Tue Mar 7 16:20:35 2006 New Revision: 24073 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Log: done sorting listed references Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/planning.txt Tue Mar 7 16:20:35 2006 @@ -4,13 +4,13 @@ Tasks: ------ - * plan the agenda for tomorrow/thursday (Aurelien, Nicolas) +DONE plan the agenda for tomorrow/thursday (Aurelien, Nicolas) * identify parts of the current logic module that can be usefully implemented in RPython (Ludovic, Samuele) * take a look at existing logic programming software (pychinko, GECODE, CWM, tableau, pylog) and at the RETE algorithm. Think about integration (Alf, Carl Friedrich, Anders) - * existing Python syntax/new syntax: look at and update document desicribing + * existing Python syntax/new syntax: look at and update existing document * consistency for multi-paradigm programming languages (especially Python) * write a glossary for terms that occur @@ -22,16 +22,9 @@ * pychinko: http://www.mindswap.org/~katz/pychinko/ * pylog (implementation of prolog in python): http://christophe.delord.free.fr/en/pylog/ * cookbook receipt that lets one add arbitrary infix binary operators: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 - -some more (unsorted) links: - - * http://www.ps.uni-sb.de/~duchier/python/continuations.html - * http://www.jeannot.org/~js/code/index.en.html - * http://candygram.sourceforge.net/ - * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/360698 - * http://lists.logilab.org/pipermail/python-logic/2005-August/000112.html - * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303057 - * http://www.claire-language.com/doc/claire/ - * https://python.taupro.com/repo/Projects/PyIE/trunk/ - * http://www.jeannot.org/~js/code/index.en.html - + * continuations to implement backtracking search: http://www.ps.uni-sb.de/~duchier/python/continuations.html + * linear programming with nice syntactic sugar via operator overloading: http://www.jeannot.org/~js/code/index.en.html + * erlang style message-based communication and concurrency: http://candygram.sourceforge.net/ + * discussing extending python with future/promises: http://lists.logilab.org/pipermail/python-logic/2005-August/000112.html + * two python recipes that analyse and transform the bytecode of a function to interpret it as a set of facts and rules: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/360698 ; http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303057 + From mwh at codespeak.net Tue Mar 7 16:44:46 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Mar 2006 16:44:46 +0100 (CET) Subject: [pypy-svn] r24074 - pypy/dist/pypy/translator/c/test Message-ID: <20060307154446.3737010085@code0.codespeak.net> Author: mwh Date: Tue Mar 7 16:44:40 2006 New Revision: 24074 Modified: pypy/dist/pypy/translator/c/test/test_newgc.py Log: finish parameterizing this test. Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Tue Mar 7 16:44:40 2006 @@ -244,7 +244,7 @@ static_list = [] N = 100000 def f(): - for i in range(100000): + for i in range(N): a = A() a.x = i static_list.append(a) @@ -254,4 +254,4 @@ return r fn = self.getcompiled(f) res = fn() - assert res == 100000*(100000 - 1)/2 + assert res == N*(N - 1)/2 From mwh at codespeak.net Tue Mar 7 18:14:14 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Mar 2006 18:14:14 +0100 (CET) Subject: [pypy-svn] r24082 - in pypy/dist/pypy: rpython/lltypesystem rpython/memory translator/c translator/c/test Message-ID: <20060307171414.A9B9610095@code0.codespeak.net> Author: mwh Date: Tue Mar 7 18:14:11 2006 New Revision: 24082 Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/primitive.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: actually set the length field of an allocated array. this involved adding a new offset class "ArrayLengthOffset", support for that in genc, use of it in gctransform.py and actually doing the setting in MarkSweepGC.malloc (only, so far). Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/llmemory.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py Tue Mar 7 18:14:11 2006 @@ -89,6 +89,20 @@ def set(self, ob, value): raise Exception("can't assign to an array's items") +class ArrayLengthOffset(AddressOffset): + + def __init__(self, TYPE): + self.TYPE = TYPE + + def __repr__(self): + return '< ArrayLengthOffset >' + + def get(self, ob): + return len(ob) + + def set(self, ob, value): + raise Exception("can't assign to an array's length") + def sizeof(TYPE, n=None): if n is None: Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Tue Mar 7 18:14:11 2006 @@ -127,6 +127,8 @@ size_gc_header = self.size_gc_header() result = raw_malloc(size + size_gc_header) ## print "mallocing %s, size %s at %s" % (typeid, size, result) + if self.is_varsize(typeid): + (result + self.varsize_offset_to_length(typeid)).signed[0] = length self.init_gc_object(result, typeid) self.malloced_objects.append(result) self.bytes_malloced += size + size_gc_header Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Tue Mar 7 18:14:11 2006 @@ -781,7 +781,7 @@ info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) else: ARRAY = TYPE - info["ofstolength"] = 0 + info["ofstolength"] = llmemory.ArrayLengthOffset(ARRAY) info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0) assert isinstance(ARRAY, lltype.Array) offsets = offsets_to_gc_pointers(ARRAY.OF) Modified: pypy/dist/pypy/translator/c/primitive.py ============================================================================== --- pypy/dist/pypy/translator/c/primitive.py (original) +++ pypy/dist/pypy/translator/c/primitive.py Tue Mar 7 18:14:11 2006 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem.lltype import * from pypy.rpython.lltypesystem.llmemory import Address, fakeaddress, \ AddressOffset, ItemOffset, ArrayItemsOffset, FieldOffset, \ - CompositeOffset + CompositeOffset, ArrayLengthOffset from pypy.rpython.memory.gc import GCHeaderOffset from pypy.rpython.memory.lladdress import NULL @@ -24,6 +24,9 @@ elif isinstance(value, ArrayItemsOffset): return 'offsetof(%s, items)'%( db.gettype(value.TYPE).replace('@', '')) + elif isinstance(value, ArrayLengthOffset): + return 'offsetof(%s, length)'%( + db.gettype(value.TYPE).replace('@', '')) elif isinstance(value, CompositeOffset): return '%s + %s' % (name_signed(value.first, db), name_signed(value.second, db)) elif type(value) == AddressOffset: Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Tue Mar 7 18:14:11 2006 @@ -237,13 +237,12 @@ assert res == f() - def test_framework_static_roots(self): - py.test.skip("not working yet") + def test_framework_using_lists(self): class A(object): pass - static_list = [] - N = 100000 + N = 1000 def f(): + static_list = [] for i in range(N): a = A() a.x = i From cfbolz at codespeak.net Tue Mar 7 18:17:50 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Mar 2006 18:17:50 +0100 (CET) Subject: [pypy-svn] r24083 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060307171750.A699410064@code0.codespeak.net> Author: cfbolz Date: Tue Mar 7 18:17:38 2006 New Revision: 24083 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Log: (auc) add the question about logic variables/promises to the planning file Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Tue Mar 7 18:17:38 2006 @@ -57,6 +57,7 @@ lightweight concurrency and support for asynchronous messages are really very important if you want to "future-proof" Python. Monitors are terrible; transactions are nice if you can support them in the language. + discuss futures/promises versus blocking on unbound logic variables * Distributed computing (peter) A single bullet does not do it justice by a long shot. There are lots From nik at codespeak.net Tue Mar 7 20:35:16 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 7 Mar 2006 20:35:16 +0100 (CET) Subject: [pypy-svn] r24085 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060307193516.A5C691008F@code0.codespeak.net> Author: nik Date: Tue Mar 7 20:35:05 2006 New Revision: 24085 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: hacked away for a quick result of having an actual method call translated to squeak. lots of uglyness in the code now, but now i know my way around and will be able to refactor ... Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Tue Mar 7 20:35:05 2006 @@ -93,6 +93,7 @@ self.pendinggraphs = [] self.pendingclasses = [] self.pendingmethods = [] + self.pendingsetters = [] # XXX ugly. should generalize methods/setters self.classes = [] self.methods = [] self.function_container = False @@ -114,16 +115,20 @@ def gen_source(self, file): - while self.pendinggraphs or self.pendingclasses or self.pendingmethods: + while self.pendinggraphs or self.pendingclasses or self.pendingmethods \ + or self.pendingsetters: while self.pendinggraphs: graph = self.pendinggraphs.pop() self.gen_sqfunction(graph, file) while self.pendingclasses: - inst = self.pendingclasses.pop() + inst = self.pendingclasses.pop(0) self.gen_sqclass(inst, file) while self.pendingmethods: (inst, meth) = self.pendingmethods.pop() self.gen_sqmethod(inst, meth, file) + while self.pendingsetters: + (inst, field_name) = self.pendingsetters.pop() + self.gen_setter(inst, field_name, file) def gen_sqclass(self, inst, f): self.classes.append(inst) @@ -143,13 +148,31 @@ self.methods.append((inst, meth)) print >> f, "!%s methodsFor: 'methods' stamp: 'pypy 1/1/2000 00:00'!" % ( self.nameof_Instance(inst)) - print >> f, "%s" % meth - print >> f, ' "XXX methods not generated yet"' - print >> f, "! !" - print >> f + # XXX temporary hack, works only for method without arguments. + # Need to revisit selector and signature code. + print >> f, camel_case(meth) + graph = inst._methods[meth].graph + self.gen_methodbody(graph, f, do_signature=False) + def gen_setter(self, INSTANCE, field_name, f): + if (INSTANCE, field_name) in self.methods: + return + self.methods.append((INSTANCE, field_name)) + print >> f, "!%s methodsFor: 'accessors' stamp: 'pypy 1/1/2000 00:00'!" % ( + self.nameof_Instance(INSTANCE)) + print >> f, "%s: value" % field_name + print >> f, " %s := value" % field_name + print >> f, "! !" def gen_sqfunction(self, graph, f): + if not self.function_container: + self.gen_function_container(f) + self.function_container = True + print >> f, "!PyFunctions class methodsFor: 'functions'" \ + " stamp: 'pypy 1/1/2000 00:00'!" + self.gen_methodbody(graph, f) + + def gen_methodbody(self, graph, f, do_signature=True): def expr(v): if isinstance(v, Variable): @@ -174,6 +197,8 @@ receiver = args[0] name = op.args[1].value args = args[2:] + # XXX should only generate setter if field is set from outside + self.pendingsetters.append((op.args[0].concretetype, name)) else: name = op.opname receiver = args[0] @@ -242,20 +267,17 @@ yield " %s" % line yield "]" - if not self.function_container: - self.gen_function_container(f) - self.function_container = True - - start = graph.startblock - args = [expr(arg) for arg in start.inputargs] - print >> f, "!PyFunctions class methodsFor: 'functions'" \ - " stamp: 'pypy 1/1/2000 00:00'!" - print >> f, '%s' % signature(self.nameof(graph), args) + if do_signature: + args = [expr(arg) for arg in graph.startblock.inputargs] + print >> f, '%s' % signature(self.nameof(graph), args) + # XXX should declare local variables here + start = graph.startblock loops = LoopFinder(start).loops for line in render_block(start): print >> f, ' %s' % line + print >> f, '! !' print >> f def gen_function_container(self, f): @@ -323,11 +345,20 @@ #empty superclass return "Object" self.note_Instance(inst) - return "Py%s" % inst._name.capitalize() + # XXX need to properly handle package names + class_name = inst._name.split(".")[-1] + return "Py%s" % camel_case(class_name.capitalize()) + + def nameof__instance(self, _inst): + return self.nameof_Instance(_inst._TYPE) def note_Instance(self, inst): if inst not in self.classes: if inst not in self.pendingclasses: + if inst._superclass is not None: # not root + # Need to make sure that superclasses appear first in + # the generated source. + self.note_Instance(inst._superclass) self.pendingclasses.append(inst) def note_meth(self, inst, meth): Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Tue Mar 7 20:35:05 2006 @@ -4,39 +4,38 @@ from pypy.translator.test import snippet from pypy.translator.squeak.gensqueak import GenSqueak from pypy.translator.translator import TranslationContext +from pypy import conftest -def looping(i = (int), j = (int)): +def looping(i, j): while i > 0: i -= 1 while j > 0: j -= 1 -def build_sqfunc(func): +def build_sqfunc(func, args=[]): try: func = func.im_func except AttributeError: pass t = TranslationContext() - graph = t.buildflowgraph(func) - t._prebuilt_graphs[func] = graph - gen = GenSqueak(udir, t) - return gen + t.buildannotator().build_types(func, args) + t.buildrtyper(type_system="ootype").specialize() + if conftest.option.view: + t.viewcg() + return GenSqueak(udir, t) class TestSqueakTrans: def test_simple_func(self): - build_sqfunc(snippet.simple_func) + build_sqfunc(snippet.simple_func, [int]) def test_if_then_else(self): - build_sqfunc(snippet.if_then_else) - - def test_two_plus_two(self): - build_sqfunc(snippet.two_plus_two) + build_sqfunc(snippet.if_then_else, [bool, int, int]) def test_my_gcd(self): - build_sqfunc(snippet.my_gcd) + build_sqfunc(snippet.my_gcd, [int, int]) def test_looping(self): - build_sqfunc(looping) + build_sqfunc(looping, [int, int]) # For now use pipes to communicate with squeak. This is very flaky @@ -89,3 +88,11 @@ return 42 assert self.run_on_squeak(theanswer) == "42" + def test_simplemethod(self): + class A: + def m(self): + return 42 + def simplemethod(): + return A().m() + assert self.run_on_squeak(simplemethod) == "42" + From nik at codespeak.net Wed Mar 8 12:02:07 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 12:02:07 +0100 (CET) Subject: [pypy-svn] r24099 - pypy/dist/pypy/translator/squeak Message-ID: <20060308110207.E0B3710091@code0.codespeak.net> Author: nik Date: Wed Mar 8 12:02:01 2006 New Revision: 24099 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: refactoring: - get rid of nameof_FunctionGraph which was a strange beast with side-effects - move method body rendering into its own class. not sure about that design but it's definitely better than the previous nested functions approach. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 12:02:01 2006 @@ -107,7 +107,7 @@ if conftest.option.view: self.translator.view() - self.nameof(graph) #add to pending + self.pendinggraphs.append(graph) self.filename = '%s.st' % graph.name file = self.sqdir.join(self.filename).open('w') self.gen_source(file) @@ -173,109 +173,13 @@ self.gen_methodbody(graph, f) def gen_methodbody(self, graph, f, do_signature=True): - - def expr(v): - if isinstance(v, Variable): - return camel_case(v.name) - elif isinstance(v, Constant): - return self.nameof(v.value) - else: - raise TypeError, "expr(%r)" % (v,) - - def oper(op): - args = [expr(arg) for arg in op.args] - if op.opname == "oosend": - name = op.args[0].value - receiver = args[1] - args = args[2:] - self.note_meth(op.args[1].concretetype, name) - elif op.opname == "oogetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - elif op.opname == "oosetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - # XXX should only generate setter if field is set from outside - self.pendingsetters.append((op.args[0].concretetype, name)) - else: - name = op.opname - receiver = args[0] - args = args[1:] - argnames = ['with'] * len(args) - if argnames: - argnames[0] = '' - sel = selector(name, argnames) - if op.opname != "oosend": - sel = selectormap.get(sel, sel) - return "%s := %s %s." % (expr(op.result), receiver, signature(sel, args)) - - def render_return(args): - if len(args) == 2: - # exception - exc_cls = expr(args[0]) - exc_val = expr(args[1]) - yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) - else: - # regular return block - retval = expr(args[0]) - yield "^%s" % retval - - def render_link(link): - block = link.target - if link.args: - for i in range(len(link.args)): - yield '%s := %s.' % (expr(block.inputargs[i]), expr(link.args[i])) - for line in render_block(block): - yield line - - def render_block(block): - if loops.has_key(block): - if not loops[block]: - yield '"skip1"' - return - yield "[" - for op in block.operations: - yield "%s" % oper(op) - if len(block.exits) == 0: - for line in render_return(block.inputargs): - yield line - return - elif block.exitswitch is None: - # single-exit block - assert len(block.exits) == 1 - for line in render_link(block.exits[0]): - yield line - else: - #exitswitch - if loops.has_key(block): - if loops[block]: - loops[block] = False - yield "%s] whileTrue: [" % expr(block.exitswitch) - for line in render_link(block.exits[True]): - yield " %s" % line - yield "]." - for line in render_link(block.exits[False]): - yield "%s" % line - else: - yield "%s ifTrue: [" % expr(block.exitswitch) - for line in render_link(block.exits[True]): - yield " %s" % line - yield "] ifFalse: [" - for line in render_link(block.exits[False]): - yield " %s" % line - yield "]" - if do_signature: - args = [expr(arg) for arg in graph.startblock.inputargs] - print >> f, '%s' % signature(self.nameof(graph), args) - # XXX should declare local variables here + # XXX only works for functions without arguments + name = self.unique_name(graph.name.split('.')[-1]) + print >> f, name - start = graph.startblock - loops = LoopFinder(start).loops - - for line in render_block(start): + renderer = MethodBodyRenderer(self, graph) + for line in renderer.render(): print >> f, ' %s' % line print >> f, '! !' print >> f @@ -311,14 +215,6 @@ def nameof_str(self, s): return "'s'" - def nameof_FunctionGraph(self, graph): - #XXX this should actually be a StaticMeth - name = self.unique_name(graph.name.split('.')[-1]) - args = arg_names(graph) - sel = selector(name, args) - self.pendinggraphs.append(graph) - return sel - #def nameof_function(self, func): # #XXX this should actually be a StaticMeth # printable_name = '(%s:%d) %s' % ( @@ -381,3 +277,113 @@ # that raises an exception when called. name = self.unique_name(camel_case('skipped_' + func.__name__)) return name + + +class MethodBodyRenderer: + + def __init__(self, gen, graph): + self.gen = gen + self.start = graph.startblock + self.loops = LoopFinder(self.start).loops + + def render(self): + # XXX should declare local variables here + for line in self.render_block(self.start): + yield line + + def expr(self, v): + if isinstance(v, Variable): + return camel_case(v.name) + elif isinstance(v, Constant): + return self.gen.nameof(v.value) + else: + raise TypeError, "expr(%r)" % (v,) + + def oper(self, op): + args = [self.expr(arg) for arg in op.args] + if op.opname == "oosend": + name = op.args[0].value + receiver = args[1] + args = args[2:] + self.gen.note_meth(op.args[1].concretetype, name) + elif op.opname == "oogetfield": + receiver = args[0] + name = op.args[1].value + args = args[2:] + elif op.opname == "oosetfield": + receiver = args[0] + name = op.args[1].value + args = args[2:] + # XXX should only generate setter if field is set from outside + self.gen.pendingsetters.append((op.args[0].concretetype, name)) + else: + name = op.opname + receiver = args[0] + args = args[1:] + argnames = ['with'] * len(args) + if argnames: + argnames[0] = '' + sel = selector(name, argnames) + if op.opname != "oosend": + sel = selectormap.get(sel, sel) + return "%s := %s %s." \ + % (self.expr(op.result), receiver, signature(sel, args)) + + def render_return(self, args): + if len(args) == 2: + # exception + exc_cls = self.expr(args[0]) + exc_val = self.expr(args[1]) + yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) + else: + # regular return block + retval = self.expr(args[0]) + yield "^%s" % retval + + def render_link(self, link): + block = link.target + if link.args: + for i in range(len(link.args)): + yield '%s := %s.' % \ + (self.expr(block.inputargs[i]), self.expr(link.args[i])) + for line in self.render_block(block): + yield line + + def render_block(self, block): + if self.loops.has_key(block): + if not self.loops[block]: + yield '"skip1"' + return + yield "[" + for op in block.operations: + yield "%s" % self.oper(op) + if len(block.exits) == 0: + for line in self.render_return(block.inputargs): + yield line + return + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for line in self.render_link(block.exits[0]): + yield line + else: + #exitswitch + if self.loops.has_key(block): + if self.loops[block]: + self.loops[block] = False + yield "%s] whileTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "]." + for line in self.render_link(block.exits[False]): + yield "%s" % line + else: + yield "%s ifTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "] ifFalse: [" + for line in self.render_link(block.exits[False]): + yield " %s" % line + yield "]" + + From mwh at codespeak.net Wed Mar 8 14:29:27 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Mar 2006 14:29:27 +0100 (CET) Subject: [pypy-svn] r24102 - in pypy/dist/pypy: rpython/memory translator/c translator/c/test Message-ID: <20060308132927.BFCF01008E@code0.codespeak.net> Author: mwh Date: Wed Mar 8 14:29:26 2006 New Revision: 24102 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/gc.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: so. make a test using a static root pass. the easy part, it turned out was finding the static roots and making sure they were always part of the root set. the harder part was realizing that there was a bug in FrameworkGcPolicy.common_gcheader_initdata -- in the case of an embedded structure you don't want the typeid to be that of the embedded structure, you want it to be that of the structure doint the embedding. the most aggravating part of all this was that i wasn't finding the types of all the constants present in the graph, so I work harder. i'm not sure i've found them all yet, but the test passes at least. this would all probably have gone quicker if cfbolz had been in #pypy today -- i've basically written a stripped down version of pypy.rpython.memory.convertlltype. ho hum. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Wed Mar 8 14:29:26 2006 @@ -671,6 +671,8 @@ # set up dummy a table, to be overwritten with the real one in finish() gcdata.type_info_table = lltype.malloc(GCData.TYPE_INFO_TABLE, 0, immortal=True) + gcdata.static_roots = lltype.malloc(lltype.Array(llmemory.Address), 0, + immortal=True) self.gcdata = gcdata self.type_info_list = [] self.id_of_type = {} # {LLTYPE: type_id} @@ -706,6 +708,10 @@ q_varsize_offset_to_variable_part, q_varsize_offset_to_length, q_varsize_offsets_to_gcpointers_in_var_part) + i = 0 + while i < len(gcdata.static_roots): + push_root(gcdata.static_roots[i]) + i += 1 def push_root(addr): top = gcdata.root_stack_top @@ -726,6 +732,9 @@ data_classdef.generalize_attr( 'type_info_table', annmodel.SomePtr(lltype.Ptr(GCData.TYPE_INFO_TABLE))) + data_classdef.generalize_attr( + 'static_roots', + annmodel.SomePtr(lltype.Ptr(lltype.Array(llmemory.Address)))) annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) frameworkgc_setup_graph = annhelper.getgraph(frameworkgc_setup, [], @@ -806,15 +815,74 @@ if self.type_info_list is not None: # XXX this is a kind of sledgehammer-wallnut approach to make sure # all types get an ID. + # and to find static roots + # XXX this replicates FAR too much of pypy.rpython.memory.convertlltype :( + static_roots = {} + + seen_types = {} + + def recursive_get_types(t): + if t in seen_types: + return + seen_types[t] = True + if isinstance(t, lltype.Ptr): + recursive_get_types(t.TO) + elif isinstance(t, lltype.Struct): + if isinstance(t, lltype.GcStruct): + self.get_type_id(t) + for n in t._flds: + recursive_get_types(t._flds[n]) + elif isinstance(t, lltype.Array): + if isinstance(t, lltype.GcArray): + self.get_type_id(t) + recursive_get_types(t.OF) + + seen_constants = {} + + def recursive_get_types_from(v): + if id(v) in seen_constants: + return + print '!!!!', v + seen_constants[id(v)] = True + t = lltype.typeOf(v) + if isinstance(t, lltype.Ptr): + if v._obj: + recursive_get_types_from(v._obj) + elif isinstance(t, lltype.Struct): + if isinstance(t, lltype.GcStruct): + self.get_type_id(t) + parent = v._parentstructure() + if parent: + recursive_get_types_from(parent) + for n in t._flds: + f = getattr(t, n) + if isinstance(f, (lltype.Ptr, lltype.Struct, lltype.Array)): + recursive_get_types_from(getattr(v, n)) + elif isinstance(t, lltype.Array): + if isinstance(t, lltype.GcArray): + self.get_type_id(t) + if isinstance(t.OF, (lltype.Struct, lltype.Ptr)): + for i in v.items: + recursive_get_types_from(i) + for graph in self.translator.graphs: for block in graph.iterblocks(): - for v in block.getvariables() + block.getconstants(): + for v in block.getvariables(): + t = getattr(v, 'concretetype', None) + if t is None: + continue + recursive_get_types(v.concretetype) + for v in block.getconstants(): t = getattr(v, 'concretetype', None) if t is None: continue if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \ - t._needsgc(): - self.get_type_id(v.concretetype.TO) + t._needsgc() and find_gc_ptrs_in_type(t.TO): + static_roots[id(v.value)] = v + if isinstance(t, lltype.Ptr) and isinstance(t.TO, (lltype.Array, lltype.Struct)): + recursive_get_types_from(v.value) + elif isinstance(t, (lltype.Array, lltype.Struct)): + recursive_get_types_from(v.value) table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) @@ -840,9 +908,20 @@ ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value ll_instance.inst_type_info_table = table #self.gcdata.type_info_table = table + + ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address), + len(static_roots), + immortal=True) + static_roots = static_roots.values() + for i in range(len(static_roots)): + c = static_roots[i] + c_ll_c = rmodel.inputconst(c.concretetype, c.value) + ll_static_roots[i] = llmemory.cast_ptr_to_adr(c_ll_c.value) + ll_instance.inst_static_roots = ll_static_roots newgcdependencies = newgcdependencies or [] newgcdependencies.append(table) + newgcdependencies.append(ll_static_roots) return newgcdependencies def protect_roots(self, op, livevars): Modified: pypy/dist/pypy/translator/c/gc.py ============================================================================== --- pypy/dist/pypy/translator/c/gc.py (original) +++ pypy/dist/pypy/translator/c/gc.py Wed Mar 8 14:29:26 2006 @@ -289,4 +289,10 @@ def common_gcheader_initdata(self, defnode): # this more or less assumes mark-and-sweep gc - return [0, defnode.db.gctransformer.id_of_type[defnode.T]] + o = defnode.obj + while True: + n = o._parentstructure() + if n is None: + break + o = n + return [0, defnode.db.gctransformer.id_of_type[typeOf(o)]] Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Wed Mar 8 14:29:26 2006 @@ -254,3 +254,18 @@ fn = self.getcompiled(f) res = fn() assert res == N*(N - 1)/2 + + def test_framework_static_roots(self): + class A(object): + def __init__(self, y): + self.y = y + a = A(0) + a.x = None + def f(): + a.x = A(42) + for i in range(1000000): + A(i) + return a.x.y + fn = self.getcompiled(f) + res = fn() + assert res == 42 From ericvrp at codespeak.net Wed Mar 8 14:34:31 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 8 Mar 2006 14:34:31 +0100 (CET) Subject: [pypy-svn] r24103 - pypy/dist/pypy/translator/c Message-ID: <20060308133431.81719100A3@code0.codespeak.net> Author: ericvrp Date: Wed Mar 8 14:34:29 2006 New Revision: 24103 Modified: pypy/dist/pypy/translator/c/database.py pypy/dist/pypy/translator/c/external.py pypy/dist/pypy/translator/c/funcgen.py pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/node.py pypy/dist/pypy/translator/c/stackless.py Log: Allow multiple function generators to be attached to a FuncNode. I will use this to experiment with generate two version of functions that need stackless support. A first version will not have resume support while the second version will have both unwind and resume support. Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Wed Mar 8 14:34:29 2006 @@ -192,7 +192,7 @@ if self.latercontainerlist: work_to_do = True for node in self.latercontainerlist: - node.make_funcgen() + node.make_funcgens() self.containerlist.append(node) self.latercontainerlist = [] self.completed = True Modified: pypy/dist/pypy/translator/c/external.py ============================================================================== --- pypy/dist/pypy/translator/c/external.py (original) +++ pypy/dist/pypy/translator/c/external.py Wed Mar 8 14:34:29 2006 @@ -16,6 +16,9 @@ self.argtypenames = [db.gettype(T) for T in self.FUNCTYPE.ARGS] self.resulttypename = db.gettype(self.FUNCTYPE.RESULT) + 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))] Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Wed Mar 8 14:34:29 2006 @@ -82,6 +82,9 @@ self.vars = uniquemix self.lltypes = None + def name(self, cname): #virtual + return cname + def implementation_begin(self): db = self.db lltypes = {} Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Wed Mar 8 14:34:29 2006 @@ -728,5 +728,5 @@ \t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS) clean: -\trm -f $(OBJECTS) +\trm -f $(OBJECTS) $(TARGET) ''' Modified: pypy/dist/pypy/translator/c/node.py ============================================================================== --- pypy/dist/pypy/translator/c/node.py (original) +++ pypy/dist/pypy/translator/c/node.py Wed Mar 8 14:34:29 2006 @@ -421,7 +421,7 @@ class FuncNode(ContainerNode): nodekind = 'func' if USESLOTS: - __slots__ = """funcgen""".split() + __slots__ = """funcgens""".split() def __init__(self, db, T, obj): self.globalcontainer = True @@ -435,37 +435,38 @@ self.includes = () self.name = db.namespace.uniquename('g_' + self.basename()) if not getattr(obj, 'isgchelper', False): - self.make_funcgen() + self.make_funcgens() #self.dependencies = {} self.typename = db.gettype(T) #, who_asks=self) self.ptrname = self.name - def make_funcgen(self): - self.funcgen = select_function_code_generator(self.obj, self.db, self.name) - if self.funcgen: - argnames = self.funcgen.argnames() + 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) def basename(self): return self.obj._name def enum_dependencies(self): - if self.funcgen is None: + if not self.funcgens: return [] - return self.funcgen.allconstantvalues() + return self.funcgens[0].allconstantvalues() #Assume identical for all funcgens def forward_declaration(self): - if self.funcgen: - return ContainerNode.forward_declaration(self) - else: - return [] + for funcgen in self.funcgens: + yield '%s;' % ( + cdecl(self.implementationtypename, funcgen.name(self.name))) def implementation(self): - funcgen = self.funcgen - if funcgen is None: - return + for funcgen in self.funcgens: + for s in self.funcgen_implementation(funcgen): + yield s + + def funcgen_implementation(self, funcgen): funcgen.implementation_begin() - yield '%s {' % cdecl(self.implementationtypename, self.name) + yield '%s {' % cdecl(self.implementationtypename, funcgen.name(self.name)) # # declare the local variables # @@ -508,30 +509,36 @@ assert not USESLOTS or '__dict__' not in dir(FuncNode) -def select_function_code_generator(fnobj, db, functionname): +def select_function_code_generators(fnobj, db, functionname): if fnobj._callable in extfunc.EXTERNALS: # 'fnobj' is one of the ll_xyz() functions with the suggested_primitive # flag in pypy.rpython.module.*. The corresponding C wrappers are # written by hand in src/ll_*.h, and declared in extfunc.EXTERNALS. db.externalfuncs[fnobj._callable] = fnobj - return None + return [] elif getattr(fnobj._callable, 'suggested_primitive', False): raise ValueError, "trying to compile suggested primitive %r" % ( fnobj._callable,) elif hasattr(fnobj, 'graph'): cpython_exc = getattr(fnobj, 'exception_policy', None) == "CPython" if hasattr(db, 'stacklessdata') and not db.use_stackless_transformation: - from pypy.translator.c.stackless import SlpFunctionCodeGenerator - gencls = SlpFunctionCodeGenerator + split_slp_function = False + if split_slp_function: + from pypy.translator.c.stackless import SlpSaveOnlyFunctionCodeGenerator, \ + SlpResumeFunctionCodeGenerator + return [SlpSaveOnlyFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname), + SlpResumeFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] + else: + from pypy.translator.c.stackless import SlpFunctionCodeGenerator + return [SlpFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] else: - gencls = FunctionCodeGenerator - return gencls(fnobj.graph, db, cpython_exc, functionname) + return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] elif getattr(fnobj, 'external', None) == 'C': # deprecated case if getattr(fnobj, 'includes', None): - return None # assume no wrapper needed + return [] # assume no wrapper needed else: - return CExternalFunctionCodeGenerator(fnobj, db) + return [CExternalFunctionCodeGenerator(fnobj, db)] else: raise ValueError, "don't know how to generate code for %r" % (fnobj,) Modified: pypy/dist/pypy/translator/c/stackless.py ============================================================================== --- pypy/dist/pypy/translator/c/stackless.py (original) +++ pypy/dist/pypy/translator/c/stackless.py Wed Mar 8 14:34:29 2006 @@ -211,6 +211,7 @@ class SlpFunctionCodeGenerator(FunctionCodeGenerator): + needs_resume = True def cfunction_body(self): # lists filled by check_directcall_result() from super.cfunction_body() @@ -219,13 +220,16 @@ body = list(super(SlpFunctionCodeGenerator, self).cfunction_body()) # if self.savelines: # header (if we need to resume) - yield 'if (slp_frame_stack_top) goto resume;' + if self.needs_resume: + yield 'if (slp_frame_stack_top) goto resume;' for line in body: # regular body yield line if self.savelines: yield '' for line in self.savelines: # save-state-away lines yield line + if not self.needs_resume: + return yield '' yield 'resume:' # resume-state blocks yield '{' @@ -247,7 +251,7 @@ argtypes = [T for T in argtypes if T is not lltype.Void] rettype = signature_type(self.lltypemap(self.graph.getreturnvar())) FUNC = lltype.FuncType(argtypes, rettype) - slpdata.registerunwindable(self.functionname, FUNC, + slpdata.registerunwindable(self.name(self.functionname), FUNC, resume_points = len(self.resumeblocks)) del self.savelines @@ -346,6 +350,17 @@ return line +class SlpSaveOnlyFunctionCodeGenerator(SlpFunctionCodeGenerator): + needs_resume = False + + +class SlpResumeFunctionCodeGenerator(SlpFunctionCodeGenerator): + needs_resume = True + + def name(self, cname): + return cname + '_SlpResume' + + def signature_type(T): """Return T unless it's a pointer type, in which case we return a general basic pointer type. From mwh at codespeak.net Wed Mar 8 15:04:05 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Mar 2006 15:04:05 +0100 (CET) Subject: [pypy-svn] r24106 - pypy/dist/pypy/translator/c/test Message-ID: <20060308140405.6473B100A9@code0.codespeak.net> Author: mwh Date: Wed Mar 8 15:04:04 2006 New Revision: 24106 Modified: pypy/dist/pypy/translator/c/test/test_newgc.py Log: a skipped test that i don't know how to make pass Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Wed Mar 8 15:04:04 2006 @@ -269,3 +269,19 @@ fn = self.getcompiled(f) res = fn() assert res == 42 + + def test_framework_nongc_static_root(self): + py.test.skip("I don't know how to make this work") + S = lltype.GcStruct("S", ('x', lltype.Signed)) + T = lltype.Struct("T", ('p', lltype.Ptr(S))) + t = lltype.malloc(T, immortal=True) + def f(): + t.p = lltype.malloc(S) + t.p.x = 43 + for i in range(1000000): + s = lltype.malloc(S) + s.x = i + return t.p.x + fn = self.getcompiled(f) + res = fn() + assert res == 43 From nik at codespeak.net Wed Mar 8 15:40:17 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 15:40:17 +0100 (CET) Subject: [pypy-svn] r24108 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060308144017.B338C100A9@code0.codespeak.net> Author: nik Date: Wed Mar 8 15:40:16 2006 New Revision: 24108 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: - generalize function/method calls with arguments and make them actually work - factor out function/selector mapping and signature generation into class Selector - make squeak tunneling for tests nicer and support arguments Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 15:40:16 2006 @@ -7,21 +7,9 @@ from pypy.translator.simplify import simplify_graph from pypy import conftest -selectormap = { - 'setitem:with:': 'at:put:', - 'getitem:': 'at:', - 'new': 'new', - 'runtimenew': 'new', - 'classof': 'class', - 'sameAs': 'yourself', - 'intAdd:': '+', -} - def camel_case(str): words = str.split('_') - for i in range(1, len(words)): - words[i] = words[i].capitalize() - return ''.join(words) + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) def arg_names(graph): #XXX need to handle more args, see @@ -31,28 +19,49 @@ assert kwarg is None return names -def selector(name, args): - s = name - if args: - s += '_' - for arg in args: - s += arg + ':' - return camel_case(s) - -def signature(sel, args): - if (':' in sel): - parts = [] - names = sel.split(':') -# assert len(names) == len(args) - while args: - parts.append(names.pop(0) + ': ' + args.pop(0)) - return ' '.join(parts) - elif not sel[0].isalnum(): -# assert len(args) == 1 - return "%s %s" %(sel, args[0]) - else: -# assert len(args) == 0 - return sel + +class Selector: + + def __init__(self, function_name, arg_count): + self.parts = [camel_case(function_name)] + self.arg_count = arg_count + self.infix = False + if not self.parts[0].isalnum(): + # Binary infix selector, e.g. "+" + assert arg_count == 1 + self.infix = True + if arg_count > 1: + self.parts += ["with"] * (arg_count - 1) + + def __str__(self): + if self.arg_count == 0 or self.infix: + return self.parts[0] + else: + return "%s:%s" % (self.parts[0], + "".join([p + ":" for p in self.parts[1:]])) + + def symbol(self): + return str(self) + + def signature(self, arg_names): + assert len(arg_names) == self.arg_count + if self.arg_count == 0: + return self.parts[0] + elif self.infix: + return "%s %s" % (self.parts[0], arg_names[0]) + else: + return " ".join(["%s: %s" % (p, a) + for (p, a) in zip(self.parts, arg_names)]) + +selectormap = { + #'setitem:with:': 'at:put:', + #'getitem:': 'at:', + 'new': Selector('new', 0), + 'runtimenew': Selector('new', 0), + 'classof': Selector('class', 0), + 'sameAs': Selector('yourself', 0), + 'intAdd:': Selector('+', 1), +} class LoopFinder: @@ -148,11 +157,8 @@ self.methods.append((inst, meth)) print >> f, "!%s methodsFor: 'methods' stamp: 'pypy 1/1/2000 00:00'!" % ( self.nameof_Instance(inst)) - # XXX temporary hack, works only for method without arguments. - # Need to revisit selector and signature code. - print >> f, camel_case(meth) graph = inst._methods[meth].graph - self.gen_methodbody(graph, f, do_signature=False) + self.gen_methodbody(camel_case(meth), graph, f) def gen_setter(self, INSTANCE, field_name, f): if (INSTANCE, field_name) in self.methods: @@ -170,17 +176,12 @@ self.function_container = True print >> f, "!PyFunctions class methodsFor: 'functions'" \ " stamp: 'pypy 1/1/2000 00:00'!" - self.gen_methodbody(graph, f) + self.gen_methodbody(graph.name, graph, f) - def gen_methodbody(self, graph, f, do_signature=True): - if do_signature: - # XXX only works for functions without arguments - name = self.unique_name(graph.name.split('.')[-1]) - print >> f, name - - renderer = MethodBodyRenderer(self, graph) + def gen_methodbody(self, method_name, graph, f): + renderer = MethodBodyRenderer(self, method_name, graph) for line in renderer.render(): - print >> f, ' %s' % line + print >> f, line print >> f, '! !' print >> f @@ -281,15 +282,21 @@ class MethodBodyRenderer: - def __init__(self, gen, graph): + def __init__(self, gen, method_name, graph): self.gen = gen + # XXX need to handle names with packages somehow, probably in Selector + self.name = method_name.split('.')[-1] self.start = graph.startblock self.loops = LoopFinder(self.start).loops def render(self): + args = self.start.inputargs + sel = Selector(self.name, len(args)) + yield sel.signature([self.expr(v) for v in args]) + # XXX should declare local variables here for line in self.render_block(self.start): - yield line + yield " %s" % line def expr(self, v): if isinstance(v, Variable): @@ -304,7 +311,9 @@ if op.opname == "oosend": name = op.args[0].value receiver = args[1] - args = args[2:] + # For now, send nil as the explicit self. XXX will probably have + # to do something more intelligent. + args = ["nil"] + args[2:] self.gen.note_meth(op.args[1].concretetype, name) elif op.opname == "oogetfield": receiver = args[0] @@ -320,14 +329,11 @@ name = op.opname receiver = args[0] args = args[1:] - argnames = ['with'] * len(args) - if argnames: - argnames[0] = '' - sel = selector(name, argnames) + sel = Selector(name, len(args)) if op.opname != "oosend": - sel = selectormap.get(sel, sel) + sel = selectormap.get(sel.symbol(), sel) return "%s := %s %s." \ - % (self.expr(op.result), receiver, signature(sel, args)) + % (self.expr(op.result), receiver, sel.signature(args)) def render_return(self, args): if len(args) == 2: Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 8 15:40:16 2006 @@ -2,7 +2,7 @@ import py from pypy.tool.udir import udir from pypy.translator.test import snippet -from pypy.translator.squeak.gensqueak import GenSqueak +from pypy.translator.squeak.gensqueak import GenSqueak, Selector from pypy.translator.translator import TranslationContext from pypy import conftest @@ -42,11 +42,16 @@ # and only works for posix systems. At some later point we'll # probably need a socket based solution for this. startup_script = """ -| stdout src function result | +| stdout src selector result arguments arg i | src := Smalltalk getSystemAttribute: 3. FileStream fileIn: src. -function := Smalltalk getSystemAttribute: 4. -result := Compiler new evaluate: ('PyFunctions ' , function) in: nil to: nil. +selector := (Smalltalk getSystemAttribute: 4) asSymbol. +arguments := OrderedCollection new. +i := 4. +[(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil] + whileTrue: [arguments add: arg asInteger]. + +result := (PyFunctions perform: selector withArguments: arguments asArray). stdout := StandardFileStream fileNamed: '/dev/stdout'. stdout nextPutAll: result asString. Smalltalk snapshot: false andQuit: true. @@ -60,7 +65,8 @@ f.write(startup_script) f.close() - def run_on_squeak(self, function): + def run_on_squeak(self, function, *args): + # NB: only integers arguments are supported currently try: import posix except ImportError: @@ -72,13 +78,13 @@ if os.getenv("SQUEAK_IMAGE") is None: py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " "variable to point to an image.") - gen_squeak = build_sqfunc(function) - squeak_process = os.popen("squeak -headless -- %s %s %s" + arg_types = [type(arg) for arg in args] + gen_squeak = build_sqfunc(function, arg_types) + cmd = 'squeak -headless -- %s %s "%s" %s' \ % (self.startup_st, udir.join(gen_squeak.filename), - # HACK XXX. Only works for functions without arguments. - # Need to really rethink how selectors are assigned - # to functions. - function.__name__)) + Selector(function.__name__, len(args)).symbol(), + " ".join(['"%s"' % a for a in args])) + squeak_process = os.popen(cmd) result = squeak_process.read() assert squeak_process.close() is None # exit status was 0 return result @@ -96,3 +102,31 @@ return A().m() assert self.run_on_squeak(simplemethod) == "42" + def test_argfunction(self): + def function(i, j=2): + return i + j + assert self.run_on_squeak(function, 1, 3) == "4" + + def test_argmethod(self): + class A: + def m(self, i, j, h=2): + return i + j + h + def simplemethod(i): + return A().m(i, j=3) + assert self.run_on_squeak(simplemethod, 1) == "6" + + +class TestSelector: + + def test_selector(self): + assert Selector("bla_bla", 0).symbol() == "blaBla" + assert Selector("bla", 1).symbol() == "bla:" + assert Selector("bla_bla_bla", 3).symbol() == "blaBlaBla:with:with:" + assert Selector("+", 1).symbol() == "+" + + def test_signature(self): + assert Selector("bla", 0).signature([]) == "bla" + assert Selector("bla", 1).signature(["v"]) == "bla: v" + assert Selector("bla", 2).signature(["v0", "v1"]) == "bla: v0 with: v1" + assert Selector("+", 1).signature(["v"]) == "+ v" + From nik at codespeak.net Wed Mar 8 15:55:33 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 15:55:33 +0100 (CET) Subject: [pypy-svn] r24111 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060308145533.D32D81008E@code0.codespeak.net> Author: nik Date: Wed Mar 8 15:55:32 2006 New Revision: 24111 Modified: pypy/dist/pypy/translator/squeak/test/test_oo.py Log: remove a test that is not really supposed to work anymore (no squeak code can be generated for a method without a graph). Modified: pypy/dist/pypy/translator/squeak/test/test_oo.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_oo.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_oo.py Wed Mar 8 15:55:32 2006 @@ -28,12 +28,6 @@ return new(C) build_sqfunc(f_new) -def test_simple_meth(): - def f_meth(): - c = new(C) - return c.m(5) - build_sqfunc(f_meth) - def test_simple_fields(): def f_fields(): c = new(C) From nik at codespeak.net Wed Mar 8 17:50:10 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 17:50:10 +0100 (CET) Subject: [pypy-svn] r24116 - in pypy/dist/pypy: rpython/ootypesystem translator/squeak translator/squeak/test Message-ID: <20060308165010.A2AB410089@code0.codespeak.net> Author: nik Date: Wed Mar 8 17:50:08 2006 New Revision: 24116 Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: always integrate package into the squeak class name. this looks really ugly in the squeak code but is probably inevitable. Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Wed Mar 8 17:50:08 2006 @@ -24,7 +24,10 @@ """this is the type of user-defined objects""" def __init__(self, name, superclass, fields={}, methods={}, _is_root=False): - self._name = name + package_parts = name.split(".") + self._name = package_parts[-1] + self._package = ".".join(package_parts[:-1]) + if _is_root: self._superclass = None else: Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Wed Mar 8 17:50:08 2006 @@ -163,7 +163,7 @@ else: b = OBJECT - self.lowleveltype = ootype.Instance(classdef.shortname, b, {}, {}) + self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}) self.prebuiltinstances = {} # { id(x): (x, _ptr) } self.object_type = self.lowleveltype Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 17:50:08 2006 @@ -237,13 +237,19 @@ # self.pendingfunctions.append(func) # return sel - def nameof_Instance(self, inst): - if inst is None: - #empty superclass + def nameof_Instance(self, INSTANCE): + if INSTANCE is None: return "Object" - self.note_Instance(inst) - # XXX need to properly handle package names - class_name = inst._name.split(".")[-1] + self.note_Instance(INSTANCE) + # For now, always integrate the package name into the + # class name. Later maybe only do this when there actually + # is a nameclash. + # NB: In theory there could be nameclashes between internal + # classes like Root with classes defined in __main__, but + # in practice it should never happen because __main__ will + # never contain user classes. + class_name = "%s_%s" \ + % (INSTANCE._package.replace(".", "_"), INSTANCE._name) return "Py%s" % camel_case(class_name.capitalize()) def nameof__instance(self, _inst): Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 8 17:50:08 2006 @@ -115,6 +115,14 @@ return A().m(i, j=3) assert self.run_on_squeak(simplemethod, 1) == "6" + def test_nameclash_classes(self): + from pypy.translator.squeak.test.support import A as A2 + class A: + def m(self, i): return 2 + i + def f(): + return A().m(0) + A2().m(0) + assert self.run_on_squeak(f) == "3" + class TestSelector: From nik at codespeak.net Wed Mar 8 18:02:30 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 18:02:30 +0100 (CET) Subject: [pypy-svn] r24118 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060308170230.814D01008B@code0.codespeak.net> Author: nik Date: Wed Mar 8 18:02:29 2006 New Revision: 24118 Added: pypy/dist/pypy/translator/squeak/test/support.py Log: forgot to check in support file for test in previous commit. Added: pypy/dist/pypy/translator/squeak/test/support.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/support.py Wed Mar 8 18:02:29 2006 @@ -0,0 +1,4 @@ +class A: + def m(self, i): + return 1 + i + From nik at codespeak.net Wed Mar 8 18:31:11 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 18:31:11 +0100 (CET) Subject: [pypy-svn] r24119 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060308173111.62876100AD@code0.codespeak.net> Author: nik Date: Wed Mar 8 18:31:10 2006 New Revision: 24119 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: avoid another type of nameclash that can occur because underlines need to be stripped from identifiers in smalltalk. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 18:31:10 2006 @@ -6,6 +6,10 @@ from pypy.translator.unsimplify import remove_direct_loops from pypy.translator.simplify import simplify_graph from pypy import conftest +try: + set +except NameError: + from sets import Set as set def camel_case(str): words = str.split('_') @@ -99,6 +103,8 @@ Constant(True).key: 'true', } self.seennames = {} + self.seen_class_names = set() + self.class_name_mapping = {} self.pendinggraphs = [] self.pendingclasses = [] self.pendingmethods = [] @@ -250,7 +256,18 @@ # never contain user classes. class_name = "%s_%s" \ % (INSTANCE._package.replace(".", "_"), INSTANCE._name) - return "Py%s" % camel_case(class_name.capitalize()) + if self.class_name_mapping.has_key(class_name): + squeak_class_name = self.class_name_mapping[class_name] + else: + class_basename = camel_case(class_name.capitalize()) + squeak_class_name = class_basename + ext = 0 + while squeak_class_name in self.seen_class_names: + squeak_class_name = class_basename + str(ext) + ext += 1 + self.class_name_mapping[class_name] = squeak_class_name + self.seen_class_names.add(squeak_class_name) + return "Py%s" % squeak_class_name def nameof__instance(self, _inst): return self.nameof_Instance(_inst._TYPE) Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 8 18:31:10 2006 @@ -123,6 +123,16 @@ return A().m(0) + A2().m(0) assert self.run_on_squeak(f) == "3" + def test_nameclash_camel_case(self): + class ASomething: + def m(self, i): return 1 + i + class Asomething: + def m(self, i): return 2 + i + def f(): + x = ASomething().m(0) + Asomething().m(0) + return x + ASomething().m(0) + Asomething().m(0) + assert self.run_on_squeak(f) == "6" + class TestSelector: From nik at codespeak.net Wed Mar 8 19:21:34 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 19:21:34 +0100 (CET) Subject: [pypy-svn] r24120 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060308182134.11F65100A3@code0.codespeak.net> Author: nik Date: Wed Mar 8 19:21:32 2006 New Revision: 24120 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/support.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: implemented direct_call llop. needed for a new failing function nameclash test. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 19:21:32 2006 @@ -111,6 +111,7 @@ self.pendingsetters = [] # XXX ugly. should generalize methods/setters self.classes = [] self.methods = [] + self.functions = [] self.function_container = False t = self.translator @@ -180,6 +181,9 @@ if not self.function_container: self.gen_function_container(f) self.function_container = True + if graph.name in self.functions: + return + self.functions.append(graph.name) print >> f, "!PyFunctions class methodsFor: 'functions'" \ " stamp: 'pypy 1/1/2000 00:00'!" self.gen_methodbody(graph.name, graph, f) @@ -269,8 +273,11 @@ self.seen_class_names.add(squeak_class_name) return "Py%s" % squeak_class_name - def nameof__instance(self, _inst): - return self.nameof_Instance(_inst._TYPE) + def nameof__instance(self, inst): + return self.nameof_Instance(inst._TYPE) + + def nameof__callable(self, callable): + return callable._name def note_Instance(self, inst): if inst not in self.classes: @@ -287,6 +294,12 @@ if bm not in self.pendingmethods: self.pendingmethods.append(bm) + def note_function(self, function): + # 'function' is actually a _static_meth (always?) + graph = function.graph + if graph not in self.pendinggraphs: + self.pendinggraphs.append(graph) + def unique_name(self, basename): n = self.seennames.get(basename, 0) self.seennames[basename] = n+1 @@ -348,6 +361,13 @@ args = args[2:] # XXX should only generate setter if field is set from outside self.gen.pendingsetters.append((op.args[0].concretetype, name)) + elif op.opname == "direct_call": + # XXX not sure if static methods of a specific class should + # be treated differently. + receiver = "PyFunctions" + name = args[0] + args = args[1:] + self.gen.note_function(op.args[0].value) else: name = op.opname receiver = args[0] Modified: pypy/dist/pypy/translator/squeak/test/support.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/support.py (original) +++ pypy/dist/pypy/translator/squeak/test/support.py Wed Mar 8 19:21:32 2006 @@ -2,3 +2,5 @@ def m(self, i): return 1 + i +def f(i): + return i + 1 Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 8 19:21:32 2006 @@ -115,6 +115,15 @@ return A().m(i, j=3) assert self.run_on_squeak(simplemethod, 1) == "6" + def test_direct_call(self): + def h(i): + return g(i) + 1 # another call to g to try to trap GenSqueak + def g(i): + return i + 1 + def f(i): + return h(i) + g(i) + assert self.run_on_squeak(f, 1) == "5" + def test_nameclash_classes(self): from pypy.translator.squeak.test.support import A as A2 class A: @@ -133,6 +142,14 @@ return x + ASomething().m(0) + Asomething().m(0) assert self.run_on_squeak(f) == "6" + def dont_test_nameclash_functions(self): + from pypy.translator.squeak.test.support import f as f2 + def f(i): + return i + 2 + def g(): + return f(0) + f2(0) + assert self.run_on_squeak(g) == "3" + class TestSelector: From nik at codespeak.net Wed Mar 8 19:55:35 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 19:55:35 +0100 (CET) Subject: [pypy-svn] r24121 - pypy/dist/pypy/translator/squeak Message-ID: <20060308185535.E4583100AC@code0.codespeak.net> Author: nik Date: Wed Mar 8 19:55:34 2006 New Revision: 24121 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: refactor generation of names for functions and push it in a convenient place to make the still skipped test for nameclashes pass soon. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 19:55:34 2006 @@ -181,9 +181,10 @@ if not self.function_container: self.gen_function_container(f) self.function_container = True - if graph.name in self.functions: + func_name = self.nameof(graph.func) + if func_name in self.functions: return - self.functions.append(graph.name) + self.functions.append(func_name) print >> f, "!PyFunctions class methodsFor: 'functions'" \ " stamp: 'pypy 1/1/2000 00:00'!" self.gen_methodbody(graph.name, graph, f) @@ -226,27 +227,6 @@ def nameof_str(self, s): return "'s'" - #def nameof_function(self, func): - # #XXX this should actually be a StaticMeth - # printable_name = '(%s:%d) %s' % ( - # func.func_globals.get('__name__', '?'), - # func.func_code.co_firstlineno, - # func.__name__) - # if self.translator.frozen: - # if func not in self.translator.flowgraphs: - # print "NOT GENERATING", printable_name - # return self.skipped_function(func) - # else: - # if (func.func_doc and - # func.func_doc.lstrip().startswith('NOT_RPYTHON')): - # print "skipped", printable_name - # return self.skipped_function(func) - # name = self.unique_name(func.__name__) - # args = arg_names(func) - # sel = selector(name, args) - # self.pendingfunctions.append(func) - # return sel - def nameof_Instance(self, INSTANCE): if INSTANCE is None: return "Object" @@ -277,8 +257,12 @@ return self.nameof_Instance(inst._TYPE) def nameof__callable(self, callable): - return callable._name + return self.nameof_function(callable.graph.func) + def nameof_function(self, function): + # XXX need to handle package names here + return function.__name__ + def note_Instance(self, inst): if inst not in self.classes: if inst not in self.pendingclasses: @@ -320,8 +304,7 @@ def __init__(self, gen, method_name, graph): self.gen = gen - # XXX need to handle names with packages somehow, probably in Selector - self.name = method_name.split('.')[-1] + self.name = method_name self.start = graph.startblock self.loops = LoopFinder(self.start).loops From nik at codespeak.net Wed Mar 8 21:20:06 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 21:20:06 +0100 (CET) Subject: [pypy-svn] r24124 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060308202006.15871100AC@code0.codespeak.net> Author: nik Date: Wed Mar 8 21:20:05 2006 New Revision: 24124 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: - unify generation of unique names for classes and function. previously skipped test passes. - remove no longer used arg_names function Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 21:20:05 2006 @@ -11,18 +11,11 @@ except NameError: from sets import Set as set -def camel_case(str): - words = str.split('_') +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) -def arg_names(graph): - #XXX need to handle more args, see - # http://docs.python.org/ref/types.html#l2h-139 - names, vararg, kwarg = graph.signature - assert vararg is None - assert kwarg is None - return names - class Selector: @@ -102,9 +95,8 @@ Constant(False).key: 'false', Constant(True).key: 'true', } - self.seennames = {} - self.seen_class_names = set() - self.class_name_mapping = {} + self.seennames = set() + self.name_mapping = {} self.pendinggraphs = [] self.pendingclasses = [] self.pendingmethods = [] @@ -182,12 +174,13 @@ self.gen_function_container(f) self.function_container = True func_name = self.nameof(graph.func) + #import pdb; pdb.set_trace() if func_name in self.functions: return self.functions.append(func_name) print >> f, "!PyFunctions class methodsFor: 'functions'" \ " stamp: 'pypy 1/1/2000 00:00'!" - self.gen_methodbody(graph.name, graph, f) + self.gen_methodbody(func_name, graph, f) def gen_methodbody(self, method_name, graph, f): renderer = MethodBodyRenderer(self, method_name, graph) @@ -238,19 +231,11 @@ # classes like Root with classes defined in __main__, but # in practice it should never happen because __main__ will # never contain user classes. - class_name = "%s_%s" \ - % (INSTANCE._package.replace(".", "_"), INSTANCE._name) - if self.class_name_mapping.has_key(class_name): - squeak_class_name = self.class_name_mapping[class_name] - else: - class_basename = camel_case(class_name.capitalize()) - squeak_class_name = class_basename - ext = 0 - while squeak_class_name in self.seen_class_names: - squeak_class_name = class_basename + str(ext) - ext += 1 - self.class_name_mapping[class_name] = squeak_class_name - self.seen_class_names.add(squeak_class_name) + class_name = INSTANCE._name + if INSTANCE._package: + class_name = "%s.%s" % (INSTANCE._package, class_name) + class_name = class_name[0].upper() + class_name[1:] + squeak_class_name = self.unique_name(class_name) return "Py%s" % squeak_class_name def nameof__instance(self, inst): @@ -260,8 +245,11 @@ return self.nameof_function(callable.graph.func) def nameof_function(self, function): - # XXX need to handle package names here - return function.__name__ + func_name = function.__name__ + if function.__module__: + func_name = "%s.%s" % (function.__module__, func_name) + squeak_func_name = self.unique_name(func_name) + return squeak_func_name def note_Instance(self, inst): if inst not in self.classes: @@ -285,13 +273,22 @@ self.pendinggraphs.append(graph) def unique_name(self, basename): - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if n == 0: - return basename + # This can be used for both classes and functions, even though + # they live in different namespaces. As long as class names + # starting with an uppercase letter are enforced, interferences + # should be seldom. + if self.name_mapping.has_key(basename): + unique = self.name_mapping[basename] else: - return self.unique_name('%s_%d' % (basename, n)) - + camel_basename = camel_case(basename) + unique = camel_basename + ext = 0 + while unique in self.seennames: + unique = camel_basename + str(ext) + ext += 1 + self.name_mapping[basename] = unique + self.seennames.add(unique) + return unique def skipped_function(self, func): # debugging only! Generates a placeholder for missing functions Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 8 21:20:05 2006 @@ -2,7 +2,7 @@ import py from pypy.tool.udir import udir from pypy.translator.test import snippet -from pypy.translator.squeak.gensqueak import GenSqueak, Selector +from pypy.translator.squeak.gensqueak import GenSqueak, Selector, camel_case from pypy.translator.translator import TranslationContext from pypy import conftest @@ -80,9 +80,11 @@ "variable to point to an image.") arg_types = [type(arg) for arg in args] gen_squeak = build_sqfunc(function, arg_types) + squeak_func_name = camel_case("%s.%s" + % (function.__module__, function.__name__)) cmd = 'squeak -headless -- %s %s "%s" %s' \ % (self.startup_st, udir.join(gen_squeak.filename), - Selector(function.__name__, len(args)).symbol(), + Selector(squeak_func_name, len(args)).symbol(), " ".join(['"%s"' % a for a in args])) squeak_process = os.popen(cmd) result = squeak_process.read() @@ -142,7 +144,7 @@ return x + ASomething().m(0) + Asomething().m(0) assert self.run_on_squeak(f) == "6" - def dont_test_nameclash_functions(self): + def test_nameclash_functions(self): from pypy.translator.squeak.test.support import f as f2 def f(i): return i + 2 From nik at codespeak.net Wed Mar 8 21:47:21 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 8 Mar 2006 21:47:21 +0100 (CET) Subject: [pypy-svn] r24125 - pypy/dist/pypy/translator/squeak Message-ID: <20060308204721.73584100AC@code0.codespeak.net> Author: nik Date: Wed Mar 8 21:47:20 2006 New Revision: 24125 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: renamings and refactorings for clarity and consistency. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 8 21:47:20 2006 @@ -1,4 +1,4 @@ -import sys +import datetime, sys from pypy.objspace.flow.model import traverse from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Constant, Variable, Block @@ -127,59 +127,60 @@ or self.pendingsetters: while self.pendinggraphs: graph = self.pendinggraphs.pop() - self.gen_sqfunction(graph, file) + self.gen_function(graph, file) while self.pendingclasses: - inst = self.pendingclasses.pop(0) - self.gen_sqclass(inst, file) + INST = self.pendingclasses.pop(0) + self.gen_class(INST, file) while self.pendingmethods: - (inst, meth) = self.pendingmethods.pop() - self.gen_sqmethod(inst, meth, file) + (INST, method_name) = self.pendingmethods.pop() + self.gen_method(INST, method_name, file) while self.pendingsetters: - (inst, field_name) = self.pendingsetters.pop() - self.gen_setter(inst, field_name, file) + (INST, field_name) = self.pendingsetters.pop() + self.gen_setter(INST, field_name, file) - def gen_sqclass(self, inst, f): - self.classes.append(inst) + def gen_fileout_header(self, class_name, category, f): + print >> f, "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( + class_name, category, + datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) + + def gen_class(self, INSTANCE, f): + self.classes.append(INSTANCE) print >> f, """%s subclass: #%s instanceVariableNames: '%s' classVariableNames: '' poolDictionaries: '' category: 'PyPy-Test'! """ % ( - self.nameof_Instance(inst._superclass), - self.nameof_Instance(inst), - ' '.join(inst._fields.iterkeys())) + self.nameof_Instance(INSTANCE._superclass), + self.nameof_Instance(INSTANCE), + ' '.join(INSTANCE._fields.iterkeys())) - def gen_sqmethod(self, inst, meth, f): - if (inst, meth) in self.methods: + def gen_method(self, INSTANCE, method_name, f): + if (INSTANCE, method_name) in self.methods: return - self.methods.append((inst, meth)) - print >> f, "!%s methodsFor: 'methods' stamp: 'pypy 1/1/2000 00:00'!" % ( - self.nameof_Instance(inst)) - graph = inst._methods[meth].graph - self.gen_methodbody(camel_case(meth), graph, f) + self.methods.append((INSTANCE, method_name)) + self.gen_fileout_header(self.nameof_Instance(INSTANCE), "methods", f) + graph = INSTANCE._methods[method_name].graph + self.gen_methodbody(camel_case(method_name), graph, f) def gen_setter(self, INSTANCE, field_name, f): if (INSTANCE, field_name) in self.methods: return self.methods.append((INSTANCE, field_name)) - print >> f, "!%s methodsFor: 'accessors' stamp: 'pypy 1/1/2000 00:00'!" % ( - self.nameof_Instance(INSTANCE)) + self.gen_fileout_header(self.nameof_Instance(INSTANCE), "accessors", f) print >> f, "%s: value" % field_name print >> f, " %s := value" % field_name print >> f, "! !" - def gen_sqfunction(self, graph, f): + def gen_function(self, graph, f): if not self.function_container: self.gen_function_container(f) self.function_container = True func_name = self.nameof(graph.func) - #import pdb; pdb.set_trace() if func_name in self.functions: return self.functions.append(func_name) - print >> f, "!PyFunctions class methodsFor: 'functions'" \ - " stamp: 'pypy 1/1/2000 00:00'!" + self.gen_fileout_header("PyFunctions class", "functions", f) self.gen_methodbody(func_name, graph, f) def gen_methodbody(self, method_name, graph, f): From cfbolz at codespeak.net Thu Mar 9 09:47:32 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 09:47:32 +0100 (CET) Subject: [pypy-svn] r24148 - pypy/dist/pypy/interpreter Message-ID: <20060309084732.97F28100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 09:47:31 2006 New Revision: 24148 Modified: pypy/dist/pypy/interpreter/gateway.py Log: pyto Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Thu Mar 9 09:47:31 2006 @@ -140,7 +140,7 @@ def check__object(self, el, orig_sig, app_sig): if el not in (int, str, float): - assert False, "unsupported basic type in uwnrap_spec" + assert False, "unsupported basic type in unwrap_spec" name = el.__name__ argname = orig_sig.next_arg() assert not argname.startswith('w_'), ( From cfbolz at codespeak.net Thu Mar 9 09:52:51 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 09:52:51 +0100 (CET) Subject: [pypy-svn] r24149 - in pypy/dist/pypy: . bin objspace objspace/test Message-ID: <20060309085251.CBD5A100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 09:52:50 2006 New Revision: 24149 Added: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Modified: pypy/dist/pypy/bin/py.py pypy/dist/pypy/conftest.py Log: add a logic object space, which is some sort of dumbed-down and sanitized version of the thunk object space: you have Variables which can be bound to other Variables and to objects. after they are bound to objects they are replaced by that object everywhere. the "forcing" of logic variables happens at the same places as in the thunk object space, although since tasklets are not quite done, we crash if we try to do an operation on unbound variables (what really should happen is that the current tasklet blocks until another tasklet binds the variable). Modified: pypy/dist/pypy/bin/py.py ============================================================================== --- pypy/dist/pypy/bin/py.py (original) +++ pypy/dist/pypy/bin/py.py Thu Mar 9 09:52:50 2006 @@ -58,6 +58,8 @@ from pypy.objspace.std import Space elif cmdlineopt.objspace == 'thunk': from pypy.objspace.thunk import Space + elif cmdlineopt.objspace == 'logic': + from pypy.objspace.logic import Space else: raise ValueError("cannot instantiate %r space" %(cmdlineopt.objspace,)) Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Thu Mar 9 09:52:50 2006 @@ -54,7 +54,7 @@ try: return _SPACECACHE[key] except KeyError: - assert name in ('std', 'thunk'), name + assert name in ('std', 'thunk', 'logic'), name mod = __import__('pypy.objspace.%s' % name, None, None, ['Space']) Space = mod.Space try: Added: pypy/dist/pypy/objspace/logic.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 09:52:50 2006 @@ -0,0 +1,97 @@ +from pypy.objspace.proxy import patch_space_in_place +from pypy.interpreter import gateway, baseobjspace, argument +from pypy.interpreter.error import OperationError +from pypy.objspace.thunk import nb_forcing_args + +# __________________________________________________________________________ + +class W_Var(baseobjspace.W_Root, object): + def __init__(w_self): + w_self.w_bound_to = None + + +def force(space, w_self): + if not isinstance(w_self, W_Var): + return w_self + w_bound_to = w_self.w_bound_to + while isinstance(w_bound_to, W_Var): + w_bound_to = w_bound_to.w_bound_to + if w_bound_to is None: + # XXX here we would have to suspend the current thread + # for now just crash + assert 0, "green threads not implemented yet" + else: + # actually attach the object directly to each variable + # to remove indirections + w_obj = w_bound_to + w_curr = w_self + while w_curr.w_bound_to is not w_obj: + w_next = w_curr.w_bound_to + w_curr.w_bound_to = w_obj + w_curr = w_next + return w_obj + +def newvar(space): + return W_Var() +app_newvar = gateway.interp2app(newvar) + +def is_unbound(space, w_var): + if not isinstance(w_var, W_Var): + return space.newbool(False) + w_curr = w_var + while isinstance(w_curr, W_Var): + w_curr = w_curr.w_bound_to + return space.newbool(w_curr is None) +app_is_unbound = gateway.interp2app(is_unbound) + +def bind(space, w_var, w_obj): + if not space.is_true(is_unbound(space, w_var)): + raise OperationError(space.w_TypeError, + space.wrap("can only bind unbound logic variable")) + w_curr = w_var + while w_curr is not None: + w_next = w_curr.w_bound_to + w_curr.w_bound_to = w_obj + w_curr = w_next + return space.w_None +app_bind = gateway.interp2app(bind) + + +# __________________________________________________________________________ + +def proxymaker(space, opname, parentfn): + nb_args = nb_forcing_args[opname] + if nb_args == 0: + proxy = None + elif nb_args == 1: + def proxy(w1, *extra): + w1 = force(space, w1) + return parentfn(w1, *extra) + elif nb_args == 2: + def proxy(w1, w2, *extra): + w1 = force(space, w1) + w2 = force(space, w2) + return parentfn(w1, w2, *extra) + elif nb_args == 3: + def proxy(w1, w2, w3, *extra): + w1 = force(space, w1) + w2 = force(space, w2) + w3 = force(space, w3) + return parentfn(w1, w2, w3, *extra) + else: + raise NotImplementedError("operation %r has arity %d" % + (opname, nb_args)) + return proxy + +def Space(*args, **kwds): + # for now, always make up a wrapped StdObjSpace + from pypy.objspace import std + space = std.Space(*args, **kwds) + patch_space_in_place(space, 'logic', proxymaker) + space.setitem(space.builtin.w_dict, space.wrap('newvar'), + space.wrap(app_newvar)) + space.setitem(space.builtin.w_dict, space.wrap('is_unbound'), + space.wrap(app_is_unbound)) + space.setitem(space.builtin.w_dict, space.wrap('bind'), + space.wrap(app_bind)) + return space Added: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Thu Mar 9 09:52:50 2006 @@ -0,0 +1,45 @@ +from pypy.conftest import gettestobjspace + +class AppTest_Logic(object): + + def setup_class(cls): + cls.space = gettestobjspace('logic') + + def test_simple(self): + X = newvar() + assert is_unbound(X) + bind(X, 1) + assert type(X) == int + assert not is_unbound(X) + assert not is_unbound(1) + raises(TypeError, bind, 1, 2) + + def test_setitem(self): + x = newvar() + d = {5: x} + d[6] = x + d[7] = [] + d[7].append(x) + y = d[5], d[6], d.values(), d.items() + for x in [d[5], d[6], d[7][0]]: + assert is_unbound(d[5]) + bind(x, 1) + for x in [d[5], d[6], d[7][0]]: + assert not is_unbound(d[5]) + + def test_unbound_unification_simple(self): + X = newvar() + Y = newvar() + bind(X, Y) + bind(X, 1) + assert X == 1 + assert Y == 1 + + def test_unbound_unification_long(self): + l = [newvar() for i in range(40)] + for i in range(39): + bind(l[i], l[i + 1]) + bind(l[20], 1) + for i in range(40): + assert l[i] == 1 + From mwh at codespeak.net Thu Mar 9 10:12:48 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 10:12:48 +0100 (CET) Subject: [pypy-svn] r24150 - pypy/dist/pypy/rpython/memory Message-ID: <20060309091248.828BE100AB@code0.codespeak.net> Author: mwh Date: Thu Mar 9 10:12:47 2006 New Revision: 24150 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: remove debugging print Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 10:12:47 2006 @@ -842,7 +842,6 @@ def recursive_get_types_from(v): if id(v) in seen_constants: return - print '!!!!', v seen_constants[id(v)] = True t = lltype.typeOf(v) if isinstance(t, lltype.Ptr): From cfbolz at codespeak.net Thu Mar 9 10:18:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 10:18:59 +0100 (CET) Subject: [pypy-svn] r24151 - in pypy/dist/pypy/objspace: . test Message-ID: <20060309091859.7668B100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 10:18:58 2006 New Revision: 24151 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: do something more sensible when trying to use a logic variable Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 10:18:58 2006 @@ -18,7 +18,8 @@ w_bound_to = w_bound_to.w_bound_to if w_bound_to is None: # XXX here we would have to suspend the current thread - # for now just crash + raise OperationError(space.w_ValueError, + space.wrap("trying to perform an operation on an unbound variable")) assert 0, "green threads not implemented yet" else: # actually attach the object directly to each variable Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Thu Mar 9 10:18:58 2006 @@ -43,3 +43,8 @@ for i in range(40): assert l[i] == 1 + def test_use_unbound_var(self): + X = newvar() + def f(x): + return x + 1 + raises(ValueError, f, X) From cfbolz at codespeak.net Thu Mar 9 10:42:53 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 10:42:53 +0100 (CET) Subject: [pypy-svn] r24153 - pypy/dist/pypy/objspace Message-ID: <20060309094253.58EA4100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 10:42:52 2006 New Revision: 24153 Modified: pypy/dist/pypy/objspace/logic.py Log: remove this unreachable assert Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 10:42:52 2006 @@ -20,7 +20,6 @@ # XXX here we would have to suspend the current thread raise OperationError(space.w_ValueError, space.wrap("trying to perform an operation on an unbound variable")) - assert 0, "green threads not implemented yet" else: # actually attach the object directly to each variable # to remove indirections From nik at codespeak.net Thu Mar 9 10:47:59 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 10:47:59 +0100 (CET) Subject: [pypy-svn] r24154 - in pypy/dist/pypy: rpython/ootypesystem rpython/ootypesystem/test rpython/test translator/squeak Message-ID: <20060309094759.2E914100AB@code0.codespeak.net> Author: nik Date: Thu Mar 9 10:47:57 2006 New Revision: 24154 Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py pypy/dist/pypy/rpython/test/test_rpbc.py pypy/dist/pypy/translator/squeak/gensqueak.py Log: remove Instance._package, leave handling of package in class name completely to backend. fix some tests that relied on previous behaviour. add a comment about possible nameclashes that can't be avoided with the current state of ootypesystem. Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Thu Mar 9 10:47:57 2006 @@ -24,9 +24,7 @@ """this is the type of user-defined objects""" def __init__(self, name, superclass, fields={}, methods={}, _is_root=False): - package_parts = name.split(".") - self._name = package_parts[-1] - self._package = ".".join(package_parts[:-1]) + self._name = name if _is_root: self._superclass = None Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py Thu Mar 9 10:47:57 2006 @@ -28,9 +28,9 @@ cls = A return cls() res = interpret(f, [0], type_system='ootype') - assert ootype.typeOf(res)._name == 'A' + assert ootype.typeOf(res)._name.split(".")[-1] == 'A' res = interpret(f, [1], type_system='ootype') - assert ootype.typeOf(res)._name == 'B' + assert ootype.typeOf(res)._name.split(".")[-1] == 'B' def test_call_classes_init(): class A: Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Thu Mar 9 10:47:57 2006 @@ -1386,7 +1386,7 @@ ts = "ootype" def class_name(self, value): - return typeOf(value)._name + return typeOf(value)._name.split(".")[-1] def read_attr(self, value, attr): return getattr(value, "o" + attr) Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 10:47:57 2006 @@ -232,9 +232,11 @@ # classes like Root with classes defined in __main__, but # in practice it should never happen because __main__ will # never contain user classes. - class_name = INSTANCE._name - if INSTANCE._package: - class_name = "%s.%s" % (INSTANCE._package, class_name) + # XXX It's impossible with the current ootypesystem to + # distinguish two equally named classes in the same + # package. For now, just hope that this never actually + # occurs within PyPy. + class_name = INSTANCE._name class_name = class_name[0].upper() + class_name[1:] squeak_class_name = self.unique_name(class_name) return "Py%s" % squeak_class_name From mwh at codespeak.net Thu Mar 9 10:56:36 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 10:56:36 +0100 (CET) Subject: [pypy-svn] r24155 - in pypy/dist/pypy/rpython/lltypesystem: . test Message-ID: <20060309095636.1E132100AB@code0.codespeak.net> Author: mwh Date: Thu Mar 9 10:56:29 2006 New Revision: 24155 Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py Log: a dissect_ll_instance generator, that returns all ll objects referred to by a given ll object. hope this helps me simplify stuff in FrameworkGCTransformer, or I've just wasted half an hour writing it... Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Thu Mar 9 10:56:29 2006 @@ -1110,5 +1110,29 @@ def typeMethod(func): func._type_method = True return func - +def dissect_ll_instance(v, memo=None): + if memo is None: + memo = {} + if id(v) in memo: + return + memo[id(v)] = True + yield v + t = typeOf(v) + if isinstance(t, Ptr): + if v._obj: + for i in dissect_ll_instance(v._obj, memo): + yield i + elif isinstance(t, Struct): + parent = v._parentstructure() + if parent: + for i in dissect_ll_instance(parent, memo): + yield i + for n in t._flds: + f = getattr(t, n) + for i in dissect_ll_instance(getattr(v, n), memo): + yield i + elif isinstance(t, Array): + for item in v.items: + for i in dissect_ll_instance(item, memo): + yield i Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py Thu Mar 9 10:56:29 2006 @@ -513,3 +513,34 @@ a = malloc(A, 10) py.test.raises(TypeError, len, a) +def test_dissect_ll_instance(): + assert list(dissect_ll_instance(1)) == [1] + GcS = GcStruct("S", ('x', Signed)) + s = malloc(GcS) + s.x = 1 + assert list(dissect_ll_instance(s)) == [s, s._obj, 1] + + A = GcArray(('x', Signed)) + a = malloc(A, 10) + for i in range(10): + a[i].x = i + expected = [a, a._obj] + for t in [(a._obj.items[i], i) for i in range(10)]: + expected.extend(t) + assert list(dissect_ll_instance(a)) == expected + + R = GcStruct("R", ('r', Ptr(GcForwardReference()))) + R.r.TO.become(R) + + r = malloc(R) + r.r = r + assert list(dissect_ll_instance(r)) == [r, r._obj] + + B = GcArray(Ptr(R)) + b = malloc(B, 2) + b[0] = b[1] = r + assert list(dissect_ll_instance(b)) == [b, b._obj, r, r._obj] + + memo = {} + assert list(dissect_ll_instance(r, memo)) == [r, r._obj] + assert list(dissect_ll_instance(b, memo)) == [b, b._obj] From ericvrp at codespeak.net Thu Mar 9 11:00:29 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 9 Mar 2006 11:00:29 +0100 (CET) Subject: [pypy-svn] r24156 - pypy/dist/pypy/translator/llvm/pyllvm/test Message-ID: <20060309100029.17ACC100AB@code0.codespeak.net> Author: ericvrp Date: Thu Mar 9 11:00:23 2006 New Revision: 24156 Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: skip llvm test for execution context because it does not work in the machines I have tried it on. Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Thu Mar 9 11:00:23 2006 @@ -1,7 +1,8 @@ +import py from pypy.translator.llvm.buildllvm import llvm_is_on_path +py.test.skip("'python setup.py build_ext -i' is not quiet working yet") if not llvm_is_on_path(): py.test.skip("llvm not found") -import py from pypy.translator.llvm.pyllvm import pyllvm def test_execution_engine(): From mwh at codespeak.net Thu Mar 9 11:17:48 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 11:17:48 +0100 (CET) Subject: [pypy-svn] r24161 - in pypy/dist/pypy/rpython: lltypesystem lltypesystem/test memory Message-ID: <20060309101748.409FE100B5@code0.codespeak.net> Author: mwh Date: Thu Mar 9 11:17:42 2006 New Revision: 24161 Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py pypy/dist/pypy/rpython/memory/gctransform.py Log: so i had to modify dissect_ll_instance to avoid calling typeOf, but it was useful for gctransform.py. dissect_ll_instance now takes a type argument and yields tuples (TYPE, ll_instance). Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Thu Mar 9 11:17:42 2006 @@ -1111,28 +1111,29 @@ func._type_method = True return func -def dissect_ll_instance(v, memo=None): +def dissect_ll_instance(v, t=None, memo=None): if memo is None: memo = {} if id(v) in memo: return memo[id(v)] = True - yield v - t = typeOf(v) + if t is None: + t = typeOf(v) + yield t, v if isinstance(t, Ptr): if v._obj: - for i in dissect_ll_instance(v._obj, memo): + for i in dissect_ll_instance(v._obj, t.TO, memo): yield i elif isinstance(t, Struct): parent = v._parentstructure() if parent: - for i in dissect_ll_instance(parent, memo): + for i in dissect_ll_instance(parent, typeOf(parent), memo): yield i for n in t._flds: f = getattr(t, n) - for i in dissect_ll_instance(getattr(v, n), memo): + for i in dissect_ll_instance(getattr(v, n), t._flds[n], memo): yield i elif isinstance(t, Array): for item in v.items: - for i in dissect_ll_instance(item, memo): + for i in dissect_ll_instance(item, t.OF, memo): yield i Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py Thu Mar 9 11:17:42 2006 @@ -514,18 +514,18 @@ py.test.raises(TypeError, len, a) def test_dissect_ll_instance(): - assert list(dissect_ll_instance(1)) == [1] + assert list(dissect_ll_instance(1)) == [(Signed, 1)] GcS = GcStruct("S", ('x', Signed)) s = malloc(GcS) s.x = 1 - assert list(dissect_ll_instance(s)) == [s, s._obj, 1] + assert list(dissect_ll_instance(s)) == [(Ptr(GcS), s), (GcS, s._obj), (Signed, 1)] A = GcArray(('x', Signed)) a = malloc(A, 10) for i in range(10): a[i].x = i - expected = [a, a._obj] - for t in [(a._obj.items[i], i) for i in range(10)]: + expected = [(Ptr(A), a), (A, a._obj)] + for t in [((A.OF, a._obj.items[i]), (Signed, i)) for i in range(10)]: expected.extend(t) assert list(dissect_ll_instance(a)) == expected @@ -534,13 +534,15 @@ r = malloc(R) r.r = r - assert list(dissect_ll_instance(r)) == [r, r._obj] + r_expected = [(Ptr(R), r), (R, r._obj)] + assert list(dissect_ll_instance(r)) == r_expected B = GcArray(Ptr(R)) b = malloc(B, 2) b[0] = b[1] = r - assert list(dissect_ll_instance(b)) == [b, b._obj, r, r._obj] + b_expected = [(Ptr(B), b), (B, b._obj)] + assert list(dissect_ll_instance(b)) == b_expected + r_expected memo = {} - assert list(dissect_ll_instance(r, memo)) == [r, r._obj] - assert list(dissect_ll_instance(b, memo)) == [b, b._obj] + assert list(dissect_ll_instance(r, None, memo)) == r_expected + assert list(dissect_ll_instance(b, None, memo)) == b_expected Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 11:17:42 2006 @@ -837,32 +837,7 @@ self.get_type_id(t) recursive_get_types(t.OF) - seen_constants = {} - - def recursive_get_types_from(v): - if id(v) in seen_constants: - return - seen_constants[id(v)] = True - t = lltype.typeOf(v) - if isinstance(t, lltype.Ptr): - if v._obj: - recursive_get_types_from(v._obj) - elif isinstance(t, lltype.Struct): - if isinstance(t, lltype.GcStruct): - self.get_type_id(t) - parent = v._parentstructure() - if parent: - recursive_get_types_from(parent) - for n in t._flds: - f = getattr(t, n) - if isinstance(f, (lltype.Ptr, lltype.Struct, lltype.Array)): - recursive_get_types_from(getattr(v, n)) - elif isinstance(t, lltype.Array): - if isinstance(t, lltype.GcArray): - self.get_type_id(t) - if isinstance(t.OF, (lltype.Struct, lltype.Ptr)): - for i in v.items: - recursive_get_types_from(i) + ll_instance_memo = {} for graph in self.translator.graphs: for block in graph.iterblocks(): @@ -878,10 +853,9 @@ if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \ t._needsgc() and find_gc_ptrs_in_type(t.TO): static_roots[id(v.value)] = v - if isinstance(t, lltype.Ptr) and isinstance(t.TO, (lltype.Array, lltype.Struct)): - recursive_get_types_from(v.value) - elif isinstance(t, (lltype.Array, lltype.Struct)): - recursive_get_types_from(v.value) + for T, inst in lltype.dissect_ll_instance(v.value, t, ll_instance_memo): + if isinstance(T, (lltype.GcArray, lltype.GcStruct)): + self.get_type_id(T) table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) From mwh at codespeak.net Thu Mar 9 11:23:35 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 11:23:35 +0100 (CET) Subject: [pypy-svn] r24162 - pypy/dist/pypy/rpython/memory Message-ID: <20060309102335.2037B100B5@code0.codespeak.net> Author: mwh Date: Thu Mar 9 11:23:34 2006 New Revision: 24162 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: tone down a comment :) Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 11:23:34 2006 @@ -816,7 +816,7 @@ # XXX this is a kind of sledgehammer-wallnut approach to make sure # all types get an ID. # and to find static roots - # XXX this replicates FAR too much of pypy.rpython.memory.convertlltype :( + # XXX this replicates too much of pypy.rpython.memory.convertlltype :( static_roots = {} seen_types = {} From ludal at codespeak.net Thu Mar 9 11:50:50 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Thu, 9 Mar 2006 11:50:50 +0100 (CET) Subject: [pypy-svn] r24165 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060309105050.07BD610089@code0.codespeak.net> Author: ludal Date: Thu Mar 9 11:50:48 2006 New Revision: 24165 Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py Log: debug deadlock? Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Thu Mar 9 11:50:48 2006 @@ -1,4 +1,5 @@ import threading +import time #----------- Exceptions --------------------------------- class VariableException(Exception): @@ -71,12 +72,31 @@ try: self._value_condition.acquire() while not self.is_bound(): - self._value_condition.wait() + t1 = time.time() + self._value_condition.wait(80) + t2 = time.time() + if t2-t1>80: + raise RuntimeError("possible deadlock??") return self.val finally: self._value_condition.release() + def reset(self): + self._value_condition.acquire() + self._val = NoValue + self._value_condition.release() + + +class StreamVar(object): + def __init__(self): + self.var = SimpleVar() + + def bind( self, val ): + newvar = SimpleVar() + self.var.bind( (val, newvar) ) + + class CsVar(SimpleVar): """Dataflow variable linked to a space""" From cfbolz at codespeak.net Thu Mar 9 12:20:23 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 12:20:23 +0100 (CET) Subject: [pypy-svn] r24167 - in pypy/dist/pypy/objspace: . test Message-ID: <20060309112023.CC13F1008B@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 12:20:21 2006 New Revision: 24167 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: (cfbolz, pedronis): experimental change to the logic object space: use == and cmp and is to unify logical variables. This is really only to get a feeling for the issues but it's actually very cool, because you can unify lists, tuples, dictionaries, and even class instances, if they have an __eq__ defined that uses equality of the __dict__ of the instances. Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 12:20:21 2006 @@ -1,7 +1,6 @@ from pypy.objspace.proxy import patch_space_in_place from pypy.interpreter import gateway, baseobjspace, argument from pypy.interpreter.error import OperationError -from pypy.objspace.thunk import nb_forcing_args # __________________________________________________________________________ @@ -9,6 +8,11 @@ def __init__(w_self): w_self.w_bound_to = None +def find_last_var_in_chain(w_var): + w_curr = w_var + while w_curr.w_bound_to is not None: + w_curr = w_curr.w_bound_to + return w_curr def force(space, w_self): if not isinstance(w_self, W_Var): @@ -45,10 +49,16 @@ app_is_unbound = gateway.interp2app(is_unbound) def bind(space, w_var, w_obj): - if not space.is_true(is_unbound(space, w_var)): + if (not isinstance(w_var, W_Var) and + not space.is_true(is_unbound(space, w_var))): raise OperationError(space.w_TypeError, space.wrap("can only bind unbound logic variable")) w_curr = w_var + if isinstance(w_obj, W_Var) and space.is_true(is_unbound(space, w_var)): + w_last1 = find_last_var_in_chain(w_var) + w_last2 = find_last_var_in_chain(w_obj) + if w_last1 is w_last2: + return space.w_None while w_curr is not None: w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj @@ -59,7 +69,95 @@ # __________________________________________________________________________ +nb_forcing_args = {} + +def setup(): + nb_forcing_args.update({ + 'setattr': 2, # instead of 3 + 'setitem': 2, # instead of 3 + 'get': 2, # instead of 3 + # ---- irregular operations ---- + 'wrap': 0, + 'str_w': 1, + 'int_w': 1, + 'float_w': 1, + 'uint_w': 1, + 'interpclass_w': 1, + 'unwrap': 1, + 'is_true': 1, + 'is_w': 2, + 'newtuple': 0, + 'newlist': 0, + 'newstring': 0, + 'newunicode': 0, + 'newdict': 0, + 'newslice': 0, + 'call_args': 1, + 'marshal_w': 1, + 'log': 1, + }) + for opname, _, arity, _ in baseobjspace.ObjSpace.MethodTable: + nb_forcing_args.setdefault(opname, arity) + for opname in baseobjspace.ObjSpace.IrregularOpTable: + assert opname in nb_forcing_args, "missing %r" % opname + +setup() +del setup + +def isoreqproxy(space, parentfn): + def isoreq(w_obj1, w_obj2): + if space.is_true(is_unbound(space, w_obj1)): + bind(space, w_obj1, w_obj2) + return space.w_True + if space.is_true(is_unbound(space, w_obj2)): + bind(space, w_obj2, w_obj1) + return space.w_True + return parentfn(force(space, w_obj1), force(space, w_obj2)) + return isoreq + +def cmpproxy(space, parentfn): + def cmp(w_obj1, w_obj2): + if space.is_true(is_unbound(space, w_obj1)): + bind(space, w_obj1, w_obj2) + return space.wrap(0) + if space.is_true(is_unbound(space, w_obj2)): + bind(space, w_obj2, w_obj1) + return space.wrap(0) + return parentfn(force(space, w_obj1), force(space, w_obj2)) + return cmp + +def neproxy(space, parentfn): + def ne(w_obj1, w_obj2): + if (isinstance(w_obj1, W_Var) and isinstance(w_obj2, W_Var) and + space.is_true(is_unbound(space, w_obj1)) and + space.is_true(is_unbound(space, w_obj2))): + w_var1 = find_last_var_in_chain(w_obj1) + w_var2 = find_last_var_in_chain(w_obj2) + if w_var1 is w_var2: + return space.w_False + return parentfn(force(space, w_obj1), force(space, w_obj2)) + return ne + +def is_wproxy(space, parentfn): + def is_w(w_obj1, w_obj2): + if space.is_true(is_unbound(space, w_obj1)): + bind(space, w_obj1, w_obj2) + return True + if space.is_true(is_unbound(space, w_obj2)): + bind(space, w_obj2, w_obj1) + return True + return parentfn(force(space, w_obj1), force(space, w_obj2)) + return is_w + def proxymaker(space, opname, parentfn): + if opname == "is_w": + return is_wproxy(space, parentfn) + if opname == "eq" or opname == "is_": + return isoreqproxy(space, parentfn) + if opname == "ne": + return neproxy(space, parentfn) + if opname == "cmp": + return cmpproxy(space, parentfn) nb_args = nb_forcing_args[opname] if nb_args == 0: proxy = None Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Thu Mar 9 12:20:21 2006 @@ -48,3 +48,41 @@ def f(x): return x + 1 raises(ValueError, f, X) + + def test_bind_to_self(self): + X = newvar() + bind(X, X) + bind(X, 1) + assert X == 1 + + def test_eq_unifies_simple(self): + X = newvar() + Y = newvar() + assert X == Y + assert X == 1 + assert not is_unbound(Y) + assert Y == 1 + + def test_ne_of_unified_vars(self): + X = newvar() + Y = newvar() + assert X == Y + assert not X != Y + + def test_cmp(self): + X = newvar() + Y = newvar() + assert cmp(X, Y) == 0 + assert is_unbound(X) + assert is_unbound(Y) + assert X == 1 + assert not is_unbound(Y) + assert Y == 1 + + def test_is(self): + X = newvar() + x = 1 + assert X is x + assert X == 1 + assert X is x + From cfbolz at codespeak.net Thu Mar 9 12:54:09 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 12:54:09 +0100 (CET) Subject: [pypy-svn] r24168 - pypy/dist/pypy/objspace Message-ID: <20060309115409.083601008B@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 12:54:07 2006 New Revision: 24168 Modified: pypy/dist/pypy/objspace/logic.py Log: refactor and simplify bind etc. to walk the chain of variables less often Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 12:54:07 2006 @@ -10,24 +10,22 @@ def find_last_var_in_chain(w_var): w_curr = w_var - while w_curr.w_bound_to is not None: + while isinstance(w_curr.w_bound_to, W_Var): w_curr = w_curr.w_bound_to return w_curr def force(space, w_self): if not isinstance(w_self, W_Var): return w_self - w_bound_to = w_self.w_bound_to - while isinstance(w_bound_to, W_Var): - w_bound_to = w_bound_to.w_bound_to - if w_bound_to is None: + w_last = find_last_var_in_chain(w_self) + w_obj = w_last.w_bound_to + if w_obj is None: # XXX here we would have to suspend the current thread raise OperationError(space.w_ValueError, space.wrap("trying to perform an operation on an unbound variable")) else: # actually attach the object directly to each variable # to remove indirections - w_obj = w_bound_to w_curr = w_self while w_curr.w_bound_to is not w_obj: w_next = w_curr.w_bound_to @@ -42,23 +40,28 @@ def is_unbound(space, w_var): if not isinstance(w_var, W_Var): return space.newbool(False) - w_curr = w_var - while isinstance(w_curr, W_Var): - w_curr = w_curr.w_bound_to - return space.newbool(w_curr is None) + w_last = find_last_var_in_chain(w_var) + return space.newbool(w_last.w_bound_to is None) app_is_unbound = gateway.interp2app(is_unbound) def bind(space, w_var, w_obj): - if (not isinstance(w_var, W_Var) and - not space.is_true(is_unbound(space, w_var))): + if not isinstance(w_var, W_Var): raise OperationError(space.w_TypeError, - space.wrap("can only bind unbound logic variable")) - w_curr = w_var - if isinstance(w_obj, W_Var) and space.is_true(is_unbound(space, w_var)): - w_last1 = find_last_var_in_chain(w_var) + space.wrap("can only bind logic variable")) + w_last = find_last_var_in_chain(w_var) + if w_last.w_bound_to is not None: + raise OperationError(space.w_TypeError, + space.wrap("can only bind unbound logic variable")) + if isinstance(w_obj, W_Var): w_last2 = find_last_var_in_chain(w_obj) - if w_last1 is w_last2: + if w_last2.w_bound_to is not None: + w_obj = w_last2 + elif w_last is w_last2: return space.w_None + else: + w_last.w_bound_to = w_last2 + return + w_curr = w_var while w_curr is not None: w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj From nik at codespeak.net Thu Mar 9 13:33:43 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 13:33:43 +0100 (CET) Subject: [pypy-svn] r24169 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060309123343.F03981008B@code0.codespeak.net> Author: nik Date: Thu Mar 9 13:33:42 2006 New Revision: 24169 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: after consulting from pedronis, make the generation of squeak unique identifiers almost ridiculously easy. package names are not integrated into class names anymore. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 13:33:42 2006 @@ -225,20 +225,8 @@ if INSTANCE is None: return "Object" self.note_Instance(INSTANCE) - # For now, always integrate the package name into the - # class name. Later maybe only do this when there actually - # is a nameclash. - # NB: In theory there could be nameclashes between internal - # classes like Root with classes defined in __main__, but - # in practice it should never happen because __main__ will - # never contain user classes. - # XXX It's impossible with the current ootypesystem to - # distinguish two equally named classes in the same - # package. For now, just hope that this never actually - # occurs within PyPy. - class_name = INSTANCE._name - class_name = class_name[0].upper() + class_name[1:] - squeak_class_name = self.unique_name(class_name) + class_name = INSTANCE._name.split(".")[-1] + squeak_class_name = self.unique_name(INSTANCE, class_name) return "Py%s" % squeak_class_name def nameof__instance(self, inst): @@ -248,10 +236,7 @@ return self.nameof_function(callable.graph.func) def nameof_function(self, function): - func_name = function.__name__ - if function.__module__: - func_name = "%s.%s" % (function.__module__, func_name) - squeak_func_name = self.unique_name(func_name) + squeak_func_name = self.unique_name(function, function.__name__) return squeak_func_name def note_Instance(self, inst): @@ -275,13 +260,9 @@ if graph not in self.pendinggraphs: self.pendinggraphs.append(graph) - def unique_name(self, basename): - # This can be used for both classes and functions, even though - # they live in different namespaces. As long as class names - # starting with an uppercase letter are enforced, interferences - # should be seldom. - if self.name_mapping.has_key(basename): - unique = self.name_mapping[basename] + def unique_name(self, key, basename): + if self.name_mapping.has_key(key): + unique = self.name_mapping[key] else: camel_basename = camel_case(basename) unique = camel_basename @@ -289,7 +270,7 @@ while unique in self.seennames: unique = camel_basename + str(ext) ext += 1 - self.name_mapping[basename] = unique + self.name_mapping[key] = unique self.seennames.add(unique) return unique Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 9 13:33:42 2006 @@ -80,11 +80,9 @@ "variable to point to an image.") arg_types = [type(arg) for arg in args] gen_squeak = build_sqfunc(function, arg_types) - squeak_func_name = camel_case("%s.%s" - % (function.__module__, function.__name__)) cmd = 'squeak -headless -- %s %s "%s" %s' \ % (self.startup_st, udir.join(gen_squeak.filename), - Selector(squeak_func_name, len(args)).symbol(), + Selector(function.__name__, len(args)).symbol(), " ".join(['"%s"' % a for a in args])) squeak_process = os.popen(cmd) result = squeak_process.read() @@ -134,6 +132,16 @@ return A().m(0) + A2().m(0) assert self.run_on_squeak(f) == "3" + def test_nameclash_classes_mean(self): + class A: + def m(self, i): return 1 + i + A2 = A + class A: + def m(self, i): return 2 + i + def f(): + return A().m(0) + A2().m(0) + assert self.run_on_squeak(f) == "3" + def test_nameclash_camel_case(self): class ASomething: def m(self, i): return 1 + i From nik at codespeak.net Thu Mar 9 13:37:26 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 13:37:26 +0100 (CET) Subject: [pypy-svn] r24170 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060309123726.9FC161008B@code0.codespeak.net> Author: nik Date: Thu Mar 9 13:37:25 2006 New Revision: 24170 Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: fix a test to actually test what it's supposed to ... Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 9 13:37:25 2006 @@ -145,11 +145,11 @@ def test_nameclash_camel_case(self): class ASomething: def m(self, i): return 1 + i - class Asomething: + class A_Something: def m(self, i): return 2 + i def f(): - x = ASomething().m(0) + Asomething().m(0) - return x + ASomething().m(0) + Asomething().m(0) + x = ASomething().m(0) + A_Something().m(0) + return x + ASomething().m(0) + A_Something().m(0) assert self.run_on_squeak(f) == "6" def test_nameclash_functions(self): From nik at codespeak.net Thu Mar 9 13:58:09 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 13:58:09 +0100 (CET) Subject: [pypy-svn] r24171 - in pypy/dist/pypy/translator: . squeak Message-ID: <20060309125809.2FC7410089@code0.codespeak.net> Author: nik Date: Thu Mar 9 13:58:08 2006 New Revision: 24171 Modified: pypy/dist/pypy/translator/gensupp.py pypy/dist/pypy/translator/squeak/gensqueak.py Log: use existing NameManager for unique names generation (thanks for the hint, cfbolz). slightly adapt it to optionally not use underscores, squeak doesn't support them in identifiers. Modified: pypy/dist/pypy/translator/gensupp.py ============================================================================== --- pypy/dist/pypy/translator/gensupp.py (original) +++ pypy/dist/pypy/translator/gensupp.py Thu Mar 9 13:58:08 2006 @@ -85,11 +85,12 @@ # while always keeping all globals visible. class NameManager(object): - def __init__(self, global_prefix=''): + def __init__(self, global_prefix='', number_sep='_'): self.seennames = {} self.scope = 0 self.scopelist = [] self.global_prefix = global_prefix + self.number_sep = number_sep def make_reserved_names(self, txt): """add names to list of known names. If one exists already, @@ -113,7 +114,7 @@ self.seennames[basename] = n+1 if with_number is None: with_number = basename in ('v', 'w_') - fmt = '%s_%d' + fmt = '%%s%s%%d' % self.number_sep if with_number and not basename[-1].isdigit(): fmt = '%s%d' if n != 0 or with_number: Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 13:58:08 2006 @@ -3,6 +3,7 @@ from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Constant, Variable, Block from pypy.objspace.flow.model import last_exception, checkgraph +from pypy.translator.gensupp import NameManager from pypy.translator.unsimplify import remove_direct_loops from pypy.translator.simplify import simplify_graph from pypy import conftest @@ -95,8 +96,8 @@ Constant(False).key: 'false', Constant(True).key: 'true', } - self.seennames = set() - self.name_mapping = {} + self.name_manager = NameManager(number_sep="") + self.unique_name_mapping = {} self.pendinggraphs = [] self.pendingclasses = [] self.pendingmethods = [] @@ -261,17 +262,12 @@ self.pendinggraphs.append(graph) def unique_name(self, key, basename): - if self.name_mapping.has_key(key): - unique = self.name_mapping[key] + if self.unique_name_mapping.has_key(key): + unique = self.unique_name_mapping[key] else: camel_basename = camel_case(basename) - unique = camel_basename - ext = 0 - while unique in self.seennames: - unique = camel_basename + str(ext) - ext += 1 - self.name_mapping[key] = unique - self.seennames.add(unique) + unique = self.name_manager.uniquename(camel_basename) + self.unique_name_mapping[key] = unique return unique def skipped_function(self, func): From cfbolz at codespeak.net Thu Mar 9 14:10:04 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 14:10:04 +0100 (CET) Subject: [pypy-svn] r24172 - pypy/extradoc/minute Message-ID: <20060309131004.9891D10089@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 14:09:48 2006 New Revision: 24172 Added: pypy/extradoc/minute/pypy-sync-2006-03-09.txt Log: minutes for todays mini-meeting Added: pypy/extradoc/minute/pypy-sync-2006-03-09.txt ============================================================================== --- (empty file) +++ pypy/extradoc/minute/pypy-sync-2006-03-09.txt Thu Mar 9 14:09:48 2006 @@ -0,0 +1,169 @@ +============================================= +pypy-sync developer meeting 09th March 2006 +============================================= + + +Attendees: Samuele around + Anders C. + Anders L. + Carl Friedrich (minutes) + Michael + Nik + Gerald + +Topics +==================== + +- activity reports (3 prepared lines of info). + Everybody submitted activity reports (see `IRC-Log`_ at the end) + There was one blocker: it seems that the people working on logic would really + like to have lightweight threads exposed to app-level (in basically any + form, for example tasklets). + +trying to get pypy-syncs to happen more regular again +------------------------------------------------------ + +Since this weeks pypy-sync was more ad-hoc than organized we should really try +to get the meetings going on more regularly again and have more people +attending. Michael volunteered to organize the next two sync meetings, Carl +Friedrich will bug him to send out invitations. Also it was decided to try to +move the sync meeting to thursday 17.00 CET to enable developers in the US to +attend. + +.. _`IRC-Log`: + +fixating sprint in Hildesheim (25th-31st July) +------------------------------------------------- + +complete log:: + + **** BEGINNE LOGBUCH UM Thu Mar 9 13:02:25 2006 + + M?r 09 13:02:25 * Du sprichst jetzt in #pypy-sync + M?r 09 13:03:05 * aleale (n=aleale at 130.104.228.188) hat #pypy-sync betreten + M?r 09 13:04:51 * mwh (n=mwh at 82-32-1-111.cable.ubr01.azte.blueyonder.co.uk) hat #pypy-sync betreten + M?r 09 13:05:03 mwh crud, i meant to write a mail yesterday about pypy-sync + M?r 09 13:06:08 cfbolz :-) + M?r 09 13:06:16 cfbolz quick lines round? or do you have issues? + M?r 09 13:06:56 aleale PREV: Sprint, jetlag + M?r 09 13:07:14 aleale NEXT: revisit pyontology + M?r 09 13:07:22 aleale Blockers: - + M?r 09 13:07:23 mwh PREV: sprint, gc hacking + M?r 09 13:07:28 mwh NEXT: more gc hacking + M?r 09 13:07:34 cfbolz LAST: vacation, logic sprint + M?r 09 13:07:34 cfbolz NEXT: logic sprint, GC work + M?r 09 13:07:34 cfbolz BLOCKER: none + M?r 09 13:07:34 mwh BLOCKERS: - + M?r 09 13:07:52 * Gromit (n=gek at code0.codespeak.net) hat #pypy-sync betreten + M?r 09 13:07:52 mwh does anyone ever have any blockers? + M?r 09 13:07:58 cfbolz yes + M?r 09 13:08:08 nikh LAST: sprint, picked up squeak backend + M?r 09 13:08:08 nikh NEXT: squeak backend + M?r 09 13:08:08 nikh BLOCKERS: still sickish + M?r 09 13:08:13 nikh yes, me ;) + M?r 09 13:08:18 mwh ah + M?r 09 13:08:24 cfbolz mwh: we actually have blockers on stackless having an applevel interface right now + M?r 09 13:08:31 arre PREV: Recovering from PyCon + M?r 09 13:08:31 arre NEXT: Non-PyPy work, maybe some JIT. + M?r 09 13:08:31 arre BLOCKERS: - + M?r 09 13:08:33 mwh oh, cool :) + M?r 09 13:08:50 mwh in some sense + M?r 09 13:09:12 cfbolz hehe + M?r 09 13:09:22 cfbolz I guess the best thing we can do to get the pypy-syncs going again is to assign next weeks moderation to someone + M?r 09 13:09:28 cfbolz and have an invitation send out + M?r 09 13:09:32 cfbolz in time + M?r 09 13:10:10 mwh i could do the next two, but then i'm on holiday + M?r 09 13:10:24 cfbolz I will try to remind you of the invitation + M?r 09 13:10:43 Gromit LAST, NEXT, BOLCKERS: Busy with other work + M?r 09 13:13:06 cfbolz meeting closed then? + M?r 09 13:13:17 arre What about moving the time of the meeting to acomodate our friends across the Atlantic? + M?r 09 13:13:33 cfbolz I would like to discuss this with more people + M?r 09 13:14:12 xorAxAx how about using the mailing list for the discussion? + M?r 09 13:14:34 mwh it's a chicken and egg situation, a bit + M?r 09 13:14:38 nikh did anyone overseas express interestin pypy-sync? + M?r 09 13:14:39 cfbolz yes + M?r 09 13:14:46 cfbolz holger :-) + M?r 09 13:14:52 mwh gene said he might + M?r 09 13:14:54 nikh ah, of course ... + M?r 09 13:15:22 cfbolz how about thursday at 16.00? + M?r 09 13:15:38 cfbolz or 17.00? + M?r 09 13:15:44 nikh 16.00 is 7 am on the west cost + M?r 09 13:15:49 nikh so better 17.00 i guess + M?r 09 13:15:59 arre 17:00 is better. + M?r 09 13:16:05 cfbolz ok with me + M?r 09 13:16:22 aleale Most weeks it will be ok (every fourth week it will be a nuissance) + M?r 09 13:16:39 Gromit ok, that's much better, it won't collide with my sync-meetings here + M?r 09 13:16:50 cfbolz good! + M?r 09 13:17:35 cfbolz then we actually have something to write a summary about :-) + M?r 09 13:17:40 cfbolz meeting closed then + M?r 09 13:18:40 * Gromit (n=gek at code0.codespeak.net) hat #pypy-sync verlassen ("Leaving") + M?r 09 13:19:16 mwh ok with me + M?r 09 13:19:20 cfbolz good + M?r 09 13:19:22 cfbolz see you then + **** BEENDE LOGBUCH UM Thu Mar 9 13:19:23 2006 + + **** BEGINNE LOGBUCH UM Thu Mar 9 13:02:25 2006 + + M?r 09 13:02:25 * Du sprichst jetzt in #pypy-sync + M?r 09 13:03:05 * aleale (n=aleale at 130.104.228.188) hat #pypy-sync betreten + M?r 09 13:04:51 * mwh (n=mwh at 82-32-1-111.cable.ubr01.azte.blueyonder.co.uk) hat #pypy-sync betreten + M?r 09 13:05:03 mwh crud, i meant to write a mail yesterday about pypy-sync + M?r 09 13:06:08 cfbolz :-) + M?r 09 13:06:16 cfbolz quick lines round? or do you have issues? + M?r 09 13:06:56 aleale PREV: Sprint, jetlag + M?r 09 13:07:14 aleale NEXT: revisit pyontology + M?r 09 13:07:22 aleale Blockers: - + M?r 09 13:07:23 mwh PREV: sprint, gc hacking + M?r 09 13:07:28 mwh NEXT: more gc hacking + M?r 09 13:07:34 cfbolz LAST: vacation, logic sprint + M?r 09 13:07:34 cfbolz NEXT: logic sprint, GC work + M?r 09 13:07:34 cfbolz BLOCKER: none + M?r 09 13:07:34 mwh BLOCKERS: - + M?r 09 13:07:52 * Gromit (n=gek at code0.codespeak.net) hat #pypy-sync betreten + M?r 09 13:07:52 mwh does anyone ever have any blockers? + M?r 09 13:07:58 cfbolz yes + M?r 09 13:08:08 nikh LAST: sprint, picked up squeak backend + M?r 09 13:08:08 nikh NEXT: squeak backend + M?r 09 13:08:08 nikh BLOCKERS: still sickish + M?r 09 13:08:13 nikh yes, me ;) + M?r 09 13:08:18 mwh ah + M?r 09 13:08:24 cfbolz mwh: we actually have blockers on stackless having an applevel interface right now + M?r 09 13:08:31 arre PREV: Recovering from PyCon + M?r 09 13:08:31 arre NEXT: Non-PyPy work, maybe some JIT. + M?r 09 13:08:31 arre BLOCKERS: - + M?r 09 13:08:33 mwh oh, cool :) + M?r 09 13:08:50 mwh in some sense + M?r 09 13:09:12 cfbolz hehe + M?r 09 13:09:22 cfbolz I guess the best thing we can do to get the pypy-syncs going again is to assign next weeks moderation to someone + M?r 09 13:09:28 cfbolz and have an invitation send out + M?r 09 13:09:32 cfbolz in time + M?r 09 13:10:10 mwh i could do the next two, but then i'm on holiday + M?r 09 13:10:24 cfbolz I will try to remind you of the invitation + M?r 09 13:10:43 Gromit LAST, NEXT, BOLCKERS: Busy with other work + M?r 09 13:13:06 cfbolz meeting closed then? + M?r 09 13:13:17 arre What about moving the time of the meeting to acomodate our friends across the Atlantic? + M?r 09 13:13:33 cfbolz I would like to discuss this with more people + M?r 09 13:14:12 xorAxAx how about using the mailing list for the discussion? + M?r 09 13:14:34 mwh it's a chicken and egg situation, a bit + M?r 09 13:14:38 nikh did anyone overseas express interestin pypy-sync? + M?r 09 13:14:39 cfbolz yes + M?r 09 13:14:46 cfbolz holger :-) + M?r 09 13:14:52 mwh gene said he might + M?r 09 13:14:54 nikh ah, of course ... + M?r 09 13:15:22 cfbolz how about thursday at 16.00? + M?r 09 13:15:38 cfbolz or 17.00? + M?r 09 13:15:44 nikh 16.00 is 7 am on the west cost + M?r 09 13:15:49 nikh so better 17.00 i guess + M?r 09 13:15:59 arre 17:00 is better. + M?r 09 13:16:05 cfbolz ok with me + M?r 09 13:16:22 aleale Most weeks it will be ok (every fourth week it will be a nuissance) + M?r 09 13:16:39 Gromit ok, that's much better, it won't collide with my sync-meetings here + M?r 09 13:16:50 cfbolz good! + M?r 09 13:17:35 cfbolz then we actually have something to write a summary about :-) + M?r 09 13:17:40 cfbolz meeting closed then + M?r 09 13:18:40 * Gromit (n=gek at code0.codespeak.net) hat #pypy-sync verlassen ("Leaving") + M?r 09 13:19:16 mwh ok with me + M?r 09 13:19:20 cfbolz good + M?r 09 13:19:22 cfbolz see you then + **** BEENDE LOGBUCH UM Thu Mar 9 13:19:23 2006 + From mwh at codespeak.net Thu Mar 9 14:22:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 14:22:15 +0100 (CET) Subject: [pypy-svn] r24173 - pypy/dist/pypy/translator/c Message-ID: <20060309132215.405A910089@code0.codespeak.net> Author: mwh Date: Thu Mar 9 14:22:14 2006 New Revision: 24173 Modified: pypy/dist/pypy/translator/c/primitive.py Log: don't ignore the .offset field in name_address ! Modified: pypy/dist/pypy/translator/c/primitive.py ============================================================================== --- pypy/dist/pypy/translator/c/primitive.py (original) +++ pypy/dist/pypy/translator/c/primitive.py Thu Mar 9 14:22:14 2006 @@ -86,10 +86,14 @@ if value is NULL: return 'NULL' assert isinstance(value, fakeaddress) - if value.ob is None: - return 'NULL' + if value.offset is None: + if value.ob is None: + return 'NULL' + else: + return db.get(value.ob) else: - return db.get(value.ob) + assert value.offset is not None + return '(void*)(((char*)(%s)) + (%s))'%(db.get(value.ob), db.get(value.offset)) PrimitiveName = { Signed: name_signed, From mwh at codespeak.net Thu Mar 9 14:25:34 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 14:25:34 +0100 (CET) Subject: [pypy-svn] r24174 - in pypy/dist/pypy: rpython/memory translator/c/test Message-ID: <20060309132534.386321008B@code0.codespeak.net> Author: mwh Date: Thu Mar 9 14:25:29 2006 New Revision: 24174 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: support for non gc static roots. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 14:25:29 2006 @@ -625,6 +625,25 @@ self.finalizer_funcptrs[TYPE] = fptr return fptr + +def gc_pointers_inside(v, adr): + t = lltype.typeOf(v) + if isinstance(t, lltype.Struct): + for n, t2 in t._flds.iteritems(): + if isinstance(t2, lltype.Ptr) and t2._needsgc() and t2.TO != lltype.PyObject: + yield adr + llmemory.offsetof(t, n) + elif isinstance(t2, (lltype.Array, lltype.Struct)): + for a in gc_pointers_inside(getattr(v, n), adr + llmemory.offsetof(t, n)): + yield a + elif isinstance(t, lltype.Array): + if isinstance(t.OF, lltype.Ptr) and t2._needsgc(): + for i in range(len(v.items)): + yield adr + llmemory.itemoffsetof(t, i) + elif isinstance(t.OF, lltype.Struct): + for i in range(len(v.items)): + for a in gc_pointers_inside(v.items[i], adr + llmemory.itemoffsetof(t, i)): + yield a + class FrameworkGCTransformer(BoehmGCTransformer): def __init__(self, translator): @@ -673,6 +692,7 @@ immortal=True) gcdata.static_roots = lltype.malloc(lltype.Array(llmemory.Address), 0, immortal=True) + gcdata.static_root_start = gcdata.static_root_end = llmemory.cast_ptr_to_adr(gcdata.static_roots) self.gcdata = gcdata self.type_info_list = [] self.id_of_type = {} # {LLTYPE: type_id} @@ -685,13 +705,19 @@ class StackRootIterator: _alloc_flavor_ = 'raw' def __init__(self): - self.current = gcdata.root_stack_top + self.stack_current = gcdata.root_stack_top + self.static_current = gcdata.static_root_start def pop(self): - while self.current != gcdata.root_stack_base: - self.current -= sizeofaddr - if self.current.address[0] != NULL: - return self.current + while self.static_current != gcdata.static_root_end: + result = self.static_current + self.static_current += sizeofaddr + if result.address[0].address[0] != NULL: + return result.address[0] + while self.stack_current != gcdata.root_stack_base: + self.stack_current -= sizeofaddr + if self.stack_current.address[0] != NULL: + return self.stack_current return NULL def frameworkgc_setup(): @@ -735,6 +761,12 @@ data_classdef.generalize_attr( 'static_roots', annmodel.SomePtr(lltype.Ptr(lltype.Array(llmemory.Address)))) + data_classdef.generalize_attr( + 'static_root_start', + annmodel.SomeAddress()) + data_classdef.generalize_attr( + 'static_root_end', + annmodel.SomeAddress()) annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) frameworkgc_setup_graph = annhelper.getgraph(frameworkgc_setup, [], @@ -817,8 +849,6 @@ # all types get an ID. # and to find static roots # XXX this replicates too much of pypy.rpython.memory.convertlltype :( - static_roots = {} - seen_types = {} def recursive_get_types(t): @@ -838,6 +868,8 @@ recursive_get_types(t.OF) ll_instance_memo = {} + static_gc_roots = {} + static_roots_inside_nongc = [] for graph in self.translator.graphs: for block in graph.iterblocks(): @@ -851,11 +883,16 @@ if t is None: continue if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \ - t._needsgc() and find_gc_ptrs_in_type(t.TO): - static_roots[id(v.value)] = v + find_gc_ptrs_in_type(t.TO): + if t._needsgc(): + static_gc_roots[id(v.value)] = v + else: + for a in gc_pointers_inside(v.value._obj, llmemory.cast_ptr_to_adr(v.value)): + static_roots_inside_nongc.append(a) for T, inst in lltype.dissect_ll_instance(v.value, t, ll_instance_memo): if isinstance(T, (lltype.GcArray, lltype.GcStruct)): self.get_type_id(T) + table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) @@ -883,18 +920,27 @@ #self.gcdata.type_info_table = table ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address), - len(static_roots), + len(static_gc_roots), immortal=True) - static_roots = static_roots.values() + static_roots = static_gc_roots.values() for i in range(len(static_roots)): c = static_roots[i] c_ll_c = rmodel.inputconst(c.concretetype, c.value) ll_static_roots[i] = llmemory.cast_ptr_to_adr(c_ll_c.value) ll_instance.inst_static_roots = ll_static_roots + + ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address), + len(static_roots_inside_nongc), + immortal=True) + for i in range(len(static_roots_inside_nongc)): + ll_static_roots_inside[i] = static_roots_inside_nongc[i] + ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address)) + ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(static_roots_inside_nongc) newgcdependencies = newgcdependencies or [] newgcdependencies.append(table) newgcdependencies.append(ll_static_roots) + newgcdependencies.append(ll_static_roots_inside) return newgcdependencies def protect_roots(self, op, livevars): Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Thu Mar 9 14:25:29 2006 @@ -271,7 +271,6 @@ assert res == 42 def test_framework_nongc_static_root(self): - py.test.skip("I don't know how to make this work") S = lltype.GcStruct("S", ('x', lltype.Signed)) T = lltype.Struct("T", ('p', lltype.Ptr(S))) t = lltype.malloc(T, immortal=True) From cfbolz at codespeak.net Thu Mar 9 14:35:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 14:35:18 +0100 (CET) Subject: [pypy-svn] r24175 - pypy/dist/pypy/objspace Message-ID: <20060309133518.0A1FE10089@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 14:35:17 2006 New Revision: 24175 Modified: pypy/dist/pypy/objspace/logic.py Log: make the annotator happy: now find_last_var_in_chain is annotated to return a W_Var Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 14:35:17 2006 @@ -10,8 +10,12 @@ def find_last_var_in_chain(w_var): w_curr = w_var - while isinstance(w_curr.w_bound_to, W_Var): - w_curr = w_curr.w_bound_to + while 1: + w_next = w_curr.w_bound_to + if isinstance(w_next, W_Var): + w_curr = w_next + else: + break return w_curr def force(space, w_self): From mwh at codespeak.net Thu Mar 9 14:52:13 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 14:52:13 +0100 (CET) Subject: [pypy-svn] r24176 - in pypy/dist/pypy/translator: . goal Message-ID: <20060309135213.27BAC10089@code0.codespeak.net> Author: mwh Date: Thu Mar 9 14:52:02 2006 New Revision: 24176 Modified: pypy/dist/pypy/translator/driver.py pypy/dist/pypy/translator/goal/translate.py Log: allow using the framework gc policy from translate.py. standalone things don't build yet. Modified: pypy/dist/pypy/translator/driver.py ============================================================================== --- pypy/dist/pypy/translator/driver.py (original) +++ pypy/dist/pypy/translator/driver.py Thu Mar 9 14:52:02 2006 @@ -219,6 +219,9 @@ if opt.gc == 'none': from pypy.translator.c import gc gcpolicy = gc.NoneGcPolicy + if opt.gc == 'framework': + from pypy.translator.c import gc + gcpolicy = gc.FrameworkGcPolicy if standalone: from pypy.translator.c.genc import CStandaloneBuilder as CBuilder Modified: pypy/dist/pypy/translator/goal/translate.py ============================================================================== --- pypy/dist/pypy/translator/goal/translate.py (original) +++ pypy/dist/pypy/translator/goal/translate.py Thu Mar 9 14:52:02 2006 @@ -48,7 +48,7 @@ '1_backend': [OPT(('-b', '--backend'), "Backend", ['c', 'llvm'])], - '2_gc': [OPT(('--gc',), "Garbage collector", ['boehm', 'ref', 'none'])], + '2_gc': [OPT(('--gc',), "Garbage collector", ['boehm', 'ref', 'framework', 'none'])], '3_stackless': [OPT(('--stackless',), "Stackless code generation", True)], '4_merge_if_blocks': [OPT(('--no-if-blocks-merge',), "Do not merge if ... elif ... chains and use a switch statement for them.", False)], }, From mwh at codespeak.net Thu Mar 9 14:59:00 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 14:59:00 +0100 (CET) Subject: [pypy-svn] r24177 - pypy/dist/pypy/rpython/memory Message-ID: <20060309135900.E638210089@code0.codespeak.net> Author: mwh Date: Thu Mar 9 14:59:00 2006 New Revision: 24177 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: oops. give a Constant() a concretetype. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 14:59:00 2006 @@ -892,7 +892,6 @@ for T, inst in lltype.dissect_ll_instance(v.value, t, ll_instance_memo): if isinstance(T, (lltype.GcArray, lltype.GcStruct)): self.get_type_id(T) - table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) @@ -973,7 +972,7 @@ newop0 = SpaceOperation( "getfield", - [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc")], + [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc", lltype.Void)], varoftype(r_gc.lowleveltype)) newop = SpaceOperation("direct_call", [self.malloc_ptr, newop0.result, c_type_id, v_length], From cfbolz at codespeak.net Thu Mar 9 15:17:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 15:17:18 +0100 (CET) Subject: [pypy-svn] r24178 - pypy/dist/pypy/objspace Message-ID: <20060309141718.4DD321008B@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 15:17:12 2006 New Revision: 24178 Modified: pypy/dist/pypy/objspace/logic.py Log: to strategic asserts to convince the annotator that W_Root does not have a w_bound_to attribute Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 15:17:12 2006 @@ -32,6 +32,7 @@ # to remove indirections w_curr = w_self while w_curr.w_bound_to is not w_obj: + assert isinstance(w_curr, W_Var) w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj w_curr = w_next @@ -67,6 +68,7 @@ return w_curr = w_var while w_curr is not None: + assert isinstance(w_curr, W_Var) w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj w_curr = w_next From cfbolz at codespeak.net Thu Mar 9 16:22:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 16:22:00 +0100 (CET) Subject: [pypy-svn] r24179 - pypy/dist/pypy/translator/goal Message-ID: <20060309152200.E32F9100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 16:21:59 2006 New Revision: 24179 Added: pypy/dist/pypy/translator/goal/targetlogicstandalone.py - copied, changed from r24168, pypy/dist/pypy/translator/goal/targetthunkstandalone.py Log: add target for translation the logic objspace From cfbolz at codespeak.net Thu Mar 9 16:23:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 16:23:30 +0100 (CET) Subject: [pypy-svn] r24180 - pypy/dist/pypy/objspace Message-ID: <20060309152330.E5EEB100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 16:23:30 2006 New Revision: 24180 Modified: pypy/dist/pypy/objspace/logic.py Log: even risking that I need to change it again: now the w_bound_to method does not move up to W_Root -- don't know whether it actually compiles Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 16:23:30 2006 @@ -31,9 +31,11 @@ # actually attach the object directly to each variable # to remove indirections w_curr = w_self - while w_curr.w_bound_to is not w_obj: + while 1: assert isinstance(w_curr, W_Var) w_next = w_curr.w_bound_to + if not isinstance(w_next, W_Var): + break w_curr.w_bound_to = w_obj w_curr = w_next return w_obj From nik at codespeak.net Thu Mar 9 16:52:20 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 16:52:20 +0100 (CET) Subject: [pypy-svn] r24181 - pypy/dist/pypy/translator/squeak Message-ID: <20060309155220.3B9AE100AF@code0.codespeak.net> Author: nik Date: Thu Mar 9 16:52:18 2006 New Revision: 24181 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: heavy gensqueak refactoring, breaking up stuff into node classes, in the spirit of genc. uff, the code finally starts to feel not awkward anymore. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 16:52:18 2006 @@ -6,6 +6,7 @@ from pypy.translator.gensupp import NameManager from pypy.translator.unsimplify import remove_direct_loops from pypy.translator.simplify import simplify_graph +from pypy.rpython.ootypesystem.ootype import Instance, ROOT from pypy import conftest try: set @@ -86,118 +87,57 @@ class GenSqueak: + sqnames = { + Constant(None).key: 'nil', + Constant(False).key: 'false', + Constant(True).key: 'true', + } + def __init__(self, sqdir, translator, modname=None): self.sqdir = sqdir self.translator = translator self.modname = (modname or translator.graphs[0].name) - self.sqnames = { - Constant(None).key: 'nil', - Constant(False).key: 'false', - Constant(True).key: 'true', - } + self.name_manager = NameManager(number_sep="") self.unique_name_mapping = {} - self.pendinggraphs = [] - self.pendingclasses = [] - self.pendingmethods = [] - self.pendingsetters = [] # XXX ugly. should generalize methods/setters - self.classes = [] - self.methods = [] - self.functions = [] - self.function_container = False - - t = self.translator - graph = t.graphs[0] - simplify_graph(graph) - remove_direct_loops(t, graph) - checkgraph(graph) + self.pending_nodes = [] + self.generated_nodes = set() if conftest.option.view: self.translator.view() - self.pendinggraphs.append(graph) + graph = self.translator.graphs[0] + self.pending_nodes.append(FunctionNode(self, graph)) self.filename = '%s.st' % graph.name file = self.sqdir.join(self.filename).open('w') self.gen_source(file) file.close() - def gen_source(self, file): - while self.pendinggraphs or self.pendingclasses or self.pendingmethods \ - or self.pendingsetters: - while self.pendinggraphs: - graph = self.pendinggraphs.pop() - self.gen_function(graph, file) - while self.pendingclasses: - INST = self.pendingclasses.pop(0) - self.gen_class(INST, file) - while self.pendingmethods: - (INST, method_name) = self.pendingmethods.pop() - self.gen_method(INST, method_name, file) - while self.pendingsetters: - (INST, field_name) = self.pendingsetters.pop() - self.gen_setter(INST, field_name, file) - - def gen_fileout_header(self, class_name, category, f): - print >> f, "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( - class_name, category, - datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) - - def gen_class(self, INSTANCE, f): - self.classes.append(INSTANCE) - print >> f, """%s subclass: #%s - instanceVariableNames: '%s' - classVariableNames: '' - poolDictionaries: '' - category: 'PyPy-Test'! - """ % ( - self.nameof_Instance(INSTANCE._superclass), - self.nameof_Instance(INSTANCE), - ' '.join(INSTANCE._fields.iterkeys())) - - def gen_method(self, INSTANCE, method_name, f): - if (INSTANCE, method_name) in self.methods: - return - self.methods.append((INSTANCE, method_name)) - self.gen_fileout_header(self.nameof_Instance(INSTANCE), "methods", f) - graph = INSTANCE._methods[method_name].graph - self.gen_methodbody(camel_case(method_name), graph, f) - - def gen_setter(self, INSTANCE, field_name, f): - if (INSTANCE, field_name) in self.methods: - return - self.methods.append((INSTANCE, field_name)) - self.gen_fileout_header(self.nameof_Instance(INSTANCE), "accessors", f) - print >> f, "%s: value" % field_name - print >> f, " %s := value" % field_name - print >> f, "! !" - - def gen_function(self, graph, f): - if not self.function_container: - self.gen_function_container(f) - self.function_container = True - func_name = self.nameof(graph.func) - if func_name in self.functions: - return - self.functions.append(func_name) - self.gen_fileout_header("PyFunctions class", "functions", f) - self.gen_methodbody(func_name, graph, f) - - def gen_methodbody(self, method_name, graph, f): - renderer = MethodBodyRenderer(self, method_name, graph) - for line in renderer.render(): + while self.pending_nodes: + node = self.pending_nodes.pop() + self.gen_node(node, file) + + def gen_node(self, node, f): + for dep in node.dependencies(): + if dep not in self.generated_nodes: + self.pending_nodes.append(node) + self.schedule_node(dep) + return + self.generated_nodes.add(node) + for line in node.render(): print >> f, line - print >> f, '! !' - print >> f + print >> f, "" + + def schedule_node(self, node): + if node not in self.generated_nodes: + if node in self.pending_nodes: + # We move the node to the front so we can enforce + # the generation of dependencies. + self.pending_nodes.remove(node) + self.pending_nodes.append(node) - def gen_function_container(self, f): - print >> f, """Object subclass: #PyFunctions - instanceVariableNames: '' - classVariableNames: '' - poolDictionaries: '' - category: 'PyPy'!""" - def nameof(self, obj): key = Constant(obj).key try: @@ -225,7 +165,7 @@ def nameof_Instance(self, INSTANCE): if INSTANCE is None: return "Object" - self.note_Instance(INSTANCE) + self.schedule_node(ClassNode(self, INSTANCE)) class_name = INSTANCE._name.split(".")[-1] squeak_class_name = self.unique_name(INSTANCE, class_name) return "Py%s" % squeak_class_name @@ -240,27 +180,6 @@ squeak_func_name = self.unique_name(function, function.__name__) return squeak_func_name - def note_Instance(self, inst): - if inst not in self.classes: - if inst not in self.pendingclasses: - if inst._superclass is not None: # not root - # Need to make sure that superclasses appear first in - # the generated source. - self.note_Instance(inst._superclass) - self.pendingclasses.append(inst) - - def note_meth(self, inst, meth): - bm = (inst, meth) - if bm not in self.methods: - if bm not in self.pendingmethods: - self.pendingmethods.append(bm) - - def note_function(self, function): - # 'function' is actually a _static_meth (always?) - graph = function.graph - if graph not in self.pendinggraphs: - self.pendinggraphs.append(graph) - def unique_name(self, key, basename): if self.unique_name_mapping.has_key(key): unique = self.unique_name_mapping[key] @@ -270,29 +189,58 @@ self.unique_name_mapping[key] = unique return unique - def skipped_function(self, func): - # debugging only! Generates a placeholder for missing functions - # that raises an exception when called. - name = self.unique_name(camel_case('skipped_' + func.__name__)) - return name +class CodeNode: + + def __hash__(self): + return hash(self.hash_key) + + def __eq__(self, other): + return isinstance(other, CodeNode) \ + and self.hash_key == other.hash_key + + # XXX need other comparison methods? -class MethodBodyRenderer: + def render_fileout_header(self, class_name, category): + return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( + class_name, category, + datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) + +class ClassNode(CodeNode): - def __init__(self, gen, method_name, graph): + def __init__(self, gen, INSTANCE): self.gen = gen - self.name = method_name - self.start = graph.startblock - self.loops = LoopFinder(self.start).loops + self.INSTANCE = INSTANCE + self.hash_key = INSTANCE + + def dependencies(self): + if self.INSTANCE._superclass is not None: # not root + return [ClassNode(self.gen, self.INSTANCE._superclass)] + else: + return [] def render(self): - args = self.start.inputargs + yield "%s subclass: #%s" % ( + self.gen.nameof_Instance(self.INSTANCE._superclass), + self.gen.nameof_Instance(self.INSTANCE)) + yield " instanceVariableNames: '%s'" % \ + ' '.join(self.INSTANCE._fields.iterkeys()) + yield " classVariableNames: ''" + yield " poolDictionaries: ''" + yield " category: 'PyPy-Test'!" + +class CallableNode(CodeNode): + + def render_body(self, startblock): + self.loops = LoopFinder(startblock).loops + args = startblock.inputargs sel = Selector(self.name, len(args)) yield sel.signature([self.expr(v) for v in args]) # XXX should declare local variables here - for line in self.render_block(self.start): + for line in self.render_block(startblock): yield " %s" % line + yield '! !' def expr(self, v): if isinstance(v, Variable): @@ -310,7 +258,8 @@ # For now, send nil as the explicit self. XXX will probably have # to do something more intelligent. args = ["nil"] + args[2:] - self.gen.note_meth(op.args[1].concretetype, name) + self.gen.schedule_node( + MethodNode(self.gen, op.args[1].concretetype, name)) elif op.opname == "oogetfield": receiver = args[0] name = op.args[1].value @@ -320,14 +269,16 @@ name = op.args[1].value args = args[2:] # XXX should only generate setter if field is set from outside - self.gen.pendingsetters.append((op.args[0].concretetype, name)) + self.gen.schedule_node( + SetterNode(self.gen, op.args[0].concretetype, name)) elif op.opname == "direct_call": # XXX not sure if static methods of a specific class should # be treated differently. receiver = "PyFunctions" name = args[0] args = args[1:] - self.gen.note_function(op.args[0].value) + self.gen.schedule_node( + FunctionNode(self.gen, op.args[0].value.graph)) else: name = op.opname receiver = args[0] @@ -395,4 +346,57 @@ yield " %s" % line yield "]" +class MethodNode(CallableNode): + + def __init__(self, gen, INSTANCE, method_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.name = method_name + self.hash_key = (INSTANCE, method_name) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof(self.INSTANCE), "methods") + graph = self.INSTANCE._methods[self.name].graph + for line in self.render_body(graph.startblock): + yield line + +class FunctionNode(CallableNode): + + FUNCTIONS = Instance("Functions", ROOT) + + def __init__(self, gen, graph): + self.gen = gen + self.graph = graph + self.name = gen.nameof(graph.func) + self.hash_key = graph + + def dependencies(self): + return [ClassNode(self.gen, self.FUNCTIONS)] + + def render(self): + yield self.render_fileout_header("PyFunctions class", "functions") + for line in self.render_body(self.graph.startblock): + yield line + +class SetterNode(CodeNode): + + def __init__(self, gen, INSTANCE, field_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.field_name = field_name + self.hash_key = (INSTANCE, field_name) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield "%s: value" % self.field_name + yield " %s := value" % self.field_name + yield "! !" From nik at codespeak.net Thu Mar 9 17:17:17 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 17:17:17 +0100 (CET) Subject: [pypy-svn] r24182 - pypy/dist/pypy/translator/squeak Message-ID: <20060309161717.BCA591008B@code0.codespeak.net> Author: nik Date: Thu Mar 9 17:17:16 2006 New Revision: 24182 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: shuffling around code within gensqueak, more sensible code order. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 17:17:16 2006 @@ -13,77 +13,6 @@ except NameError: from sets import Set as set -def camel_case(identifier): - identifier = identifier.replace(".", "_") - words = identifier.split('_') - return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) - - -class Selector: - - def __init__(self, function_name, arg_count): - self.parts = [camel_case(function_name)] - self.arg_count = arg_count - self.infix = False - if not self.parts[0].isalnum(): - # Binary infix selector, e.g. "+" - assert arg_count == 1 - self.infix = True - if arg_count > 1: - self.parts += ["with"] * (arg_count - 1) - - def __str__(self): - if self.arg_count == 0 or self.infix: - return self.parts[0] - else: - return "%s:%s" % (self.parts[0], - "".join([p + ":" for p in self.parts[1:]])) - - def symbol(self): - return str(self) - - def signature(self, arg_names): - assert len(arg_names) == self.arg_count - if self.arg_count == 0: - return self.parts[0] - elif self.infix: - return "%s %s" % (self.parts[0], arg_names[0]) - else: - return " ".join(["%s: %s" % (p, a) - for (p, a) in zip(self.parts, arg_names)]) - -selectormap = { - #'setitem:with:': 'at:put:', - #'getitem:': 'at:', - 'new': Selector('new', 0), - 'runtimenew': Selector('new', 0), - 'classof': Selector('class', 0), - 'sameAs': Selector('yourself', 0), - 'intAdd:': Selector('+', 1), -} - - -class LoopFinder: - def __init__(self, startblock): - self.loops = {} - self.parents = {startblock: startblock} - self.temps = {} - self.seen = [] - self.visit_Block(startblock) - def visit_Block(self, block, switches=[]): - #self.temps.has_key() - self.seen.append(block) - if block.exitswitch: - switches.append(block) - self.parents[block] = block - for link in block.exits: - self.visit_Link(link, switches) - def visit_Link(self, link, switches): - if link.target in switches: - self.loops[link.target] = True - if not link.target in self.seen: - self.parents[link.target] = self.parents[link.prevblock] - self.visit_Block(link.target, switches) class GenSqueak: @@ -190,6 +119,45 @@ return unique +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) + +class Selector: + + def __init__(self, function_name, arg_count): + self.parts = [camel_case(function_name)] + self.arg_count = arg_count + self.infix = False + if not self.parts[0].isalnum(): + # Binary infix selector, e.g. "+" + assert arg_count == 1 + self.infix = True + if arg_count > 1: + self.parts += ["with"] * (arg_count - 1) + + def __str__(self): + if self.arg_count == 0 or self.infix: + return self.parts[0] + else: + return "%s:%s" % (self.parts[0], + "".join([p + ":" for p in self.parts[1:]])) + + def symbol(self): + return str(self) + + def signature(self, arg_names): + assert len(arg_names) == self.arg_count + if self.arg_count == 0: + return self.parts[0] + elif self.infix: + return "%s %s" % (self.parts[0], arg_names[0]) + else: + return " ".join(["%s: %s" % (p, a) + for (p, a) in zip(self.parts, arg_names)]) + + class CodeNode: def __hash__(self): @@ -229,8 +197,43 @@ yield " poolDictionaries: ''" yield " category: 'PyPy-Test'!" +class LoopFinder: + + def __init__(self, startblock): + self.loops = {} + self.parents = {startblock: startblock} + self.temps = {} + self.seen = [] + self.visit_Block(startblock) + + def visit_Block(self, block, switches=[]): + #self.temps.has_key() + self.seen.append(block) + if block.exitswitch: + switches.append(block) + self.parents[block] = block + for link in block.exits: + self.visit_Link(link, switches) + + def visit_Link(self, link, switches): + if link.target in switches: + self.loops[link.target] = True + if not link.target in self.seen: + self.parents[link.target] = self.parents[link.prevblock] + self.visit_Block(link.target, switches) + class CallableNode(CodeNode): + selectormap = { + #'setitem:with:': 'at:put:', + #'getitem:': 'at:', + 'new': Selector('new', 0), + 'runtimenew': Selector('new', 0), + 'classof': Selector('class', 0), + 'sameAs': Selector('yourself', 0), + 'intAdd:': Selector('+', 1), + } + def render_body(self, startblock): self.loops = LoopFinder(startblock).loops args = startblock.inputargs @@ -285,7 +288,7 @@ args = args[1:] sel = Selector(name, len(args)) if op.opname != "oosend": - sel = selectormap.get(sel.symbol(), sel) + sel = self.selectormap.get(sel.symbol(), sel) return "%s := %s %s." \ % (self.expr(op.result), receiver, sel.signature(args)) From nik at codespeak.net Thu Mar 9 17:38:15 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 17:38:15 +0100 (CET) Subject: [pypy-svn] r24183 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060309163815.BC31610086@code0.codespeak.net> Author: nik Date: Thu Mar 9 17:38:14 2006 New Revision: 24183 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: made a test for accessing instance variables pass. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 17:38:14 2006 @@ -258,6 +258,8 @@ if op.opname == "oosend": name = op.args[0].value receiver = args[1] + if hasattr(self, "self") and op.args[1] == self.self: + receiver = "self" # For now, send nil as the explicit self. XXX will probably have # to do something more intelligent. args = ["nil"] + args[2:] @@ -267,8 +269,13 @@ receiver = args[0] name = op.args[1].value args = args[2:] + # XXX should only generate getter if field is set from outside + self.gen.schedule_node( + GetterNode(self.gen, op.args[0].concretetype, name)) elif op.opname == "oosetfield": receiver = args[0] + if hasattr(self, "self") and op.args[0] == self.self: + receiver = "self" name = op.args[1].value args = args[2:] # XXX should only generate setter if field is set from outside @@ -364,6 +371,7 @@ yield self.render_fileout_header( self.gen.nameof(self.INSTANCE), "methods") graph = self.INSTANCE._methods[self.name].graph + self.self = graph.startblock.inputargs[0] for line in self.render_body(graph.startblock): yield line @@ -385,17 +393,19 @@ for line in self.render_body(self.graph.startblock): yield line -class SetterNode(CodeNode): +class AccessorNode(CodeNode): def __init__(self, gen, INSTANCE, field_name): self.gen = gen self.INSTANCE = INSTANCE self.field_name = field_name - self.hash_key = (INSTANCE, field_name) + self.hash_key = (INSTANCE, field_name, self.__class__) def dependencies(self): return [ClassNode(self.gen, self.INSTANCE)] +class SetterNode(AccessorNode): + def render(self): yield self.render_fileout_header( self.gen.nameof_Instance(self.INSTANCE), "accessors") @@ -403,3 +413,12 @@ yield " %s := value" % self.field_name yield "! !" +class GetterNode(AccessorNode): + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield self.field_name + yield " ^%s" % self.field_name + yield "! !" + Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 9 17:38:14 2006 @@ -115,15 +115,6 @@ return A().m(i, j=3) assert self.run_on_squeak(simplemethod, 1) == "6" - def test_direct_call(self): - def h(i): - return g(i) + 1 # another call to g to try to trap GenSqueak - def g(i): - return i + 1 - def f(i): - return h(i) + g(i) - assert self.run_on_squeak(f, 1) == "5" - def test_nameclash_classes(self): from pypy.translator.squeak.test.support import A as A2 class A: @@ -160,6 +151,25 @@ return f(0) + f2(0) assert self.run_on_squeak(g) == "3" + def test_direct_call(self): + def h(i): + return g(i) + 1 # another call to g to try to trap GenSqueak + def g(i): + return i + 1 + def f(i): + return h(i) + g(i) + assert self.run_on_squeak(f, 1) == "5" + + def test_getfield_setfield(self): + class A: + def m(self, i): + self.i = i + def f(i): + a = A() + a.m(i) + return a.i + assert self.run_on_squeak(f, 2) == "2" + class TestSelector: From nik at codespeak.net Thu Mar 9 18:04:34 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 18:04:34 +0100 (CET) Subject: [pypy-svn] r24185 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060309170434.60CA11008B@code0.codespeak.net> Author: nik Date: Thu Mar 9 18:04:23 2006 New Revision: 24185 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: only use accessors when needed, ie if an instance variable is accessed from outside its class' methods. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 18:04:23 2006 @@ -269,18 +269,23 @@ receiver = args[0] name = op.args[1].value args = args[2:] - # XXX should only generate getter if field is set from outside - self.gen.schedule_node( - GetterNode(self.gen, op.args[0].concretetype, name)) + if hasattr(self, "self") and op.args[0] == self.self: + # Could also directly substitute op.result with name + # everywhere for optimization. + return "%s := %s." % (self.expr(op.result), name) + else: + self.gen.schedule_node( + GetterNode(self.gen, op.args[0].concretetype, name)) elif op.opname == "oosetfield": receiver = args[0] - if hasattr(self, "self") and op.args[0] == self.self: - receiver = "self" name = op.args[1].value args = args[2:] - # XXX should only generate setter if field is set from outside - self.gen.schedule_node( - SetterNode(self.gen, op.args[0].concretetype, name)) + if hasattr(self, "self") and op.args[0] == self.self: + # Note that the receiver variable is never used + return "%s := %s." % (name, args[0]) + else: + self.gen.schedule_node( + SetterNode(self.gen, op.args[0].concretetype, name)) elif op.opname == "direct_call": # XXX not sure if static methods of a specific class should # be treated differently. Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 9 18:04:23 2006 @@ -162,13 +162,18 @@ def test_getfield_setfield(self): class A: - def m(self, i): + def set(self, i): self.i = i + def inc(self): + self.i = self.i + 1 def f(i): a = A() - a.m(i) - return a.i - assert self.run_on_squeak(f, 2) == "2" + a.set(i) + i = a.i + a.i = 3 + a.inc() + return i + a.i + assert self.run_on_squeak(f, 2) == "6" class TestSelector: From nik at codespeak.net Thu Mar 9 18:21:15 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 9 Mar 2006 18:21:15 +0100 (CET) Subject: [pypy-svn] r24186 - pypy/dist/pypy/translator/squeak Message-ID: <20060309172115.D623F1008B@code0.codespeak.net> Author: nik Date: Thu Mar 9 18:21:14 2006 New Revision: 24186 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py Log: omit the explicit self from method signatures, replace it with the self keyword everywhere it's used. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 9 18:21:14 2006 @@ -236,7 +236,7 @@ def render_body(self, startblock): self.loops = LoopFinder(startblock).loops - args = startblock.inputargs + args = self.arguments(startblock) sel = Selector(self.name, len(args)) yield sel.signature([self.expr(v) for v in args]) @@ -260,9 +260,7 @@ receiver = args[1] if hasattr(self, "self") and op.args[1] == self.self: receiver = "self" - # For now, send nil as the explicit self. XXX will probably have - # to do something more intelligent. - args = ["nil"] + args[2:] + args = args[2:] self.gen.schedule_node( MethodNode(self.gen, op.args[1].concretetype, name)) elif op.opname == "oogetfield": @@ -372,6 +370,10 @@ def dependencies(self): return [ClassNode(self.gen, self.INSTANCE)] + def arguments(self, startblock): + # Omit the explicit self + return startblock.inputargs[1:] + def render(self): yield self.render_fileout_header( self.gen.nameof(self.INSTANCE), "methods") @@ -393,6 +395,9 @@ def dependencies(self): return [ClassNode(self.gen, self.FUNCTIONS)] + def arguments(self, startblock): + return startblock.inputargs + def render(self): yield self.render_fileout_header("PyFunctions class", "functions") for line in self.render_body(self.graph.startblock): From cfbolz at codespeak.net Thu Mar 9 18:29:39 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 18:29:39 +0100 (CET) Subject: [pypy-svn] r24187 - in pypy/dist/pypy/objspace: . test Message-ID: <20060309172939.A44091008B@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 18:29:28 2006 New Revision: 24187 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: (pedronis, cfbolz): slightly insane prototype using greenlets to simulate microthreads which are scheduled using the logic/dataflow variables. Warning: makes your head explode. Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 18:29:28 2006 @@ -2,7 +2,33 @@ from pypy.interpreter import gateway, baseobjspace, argument from pypy.interpreter.error import OperationError -# __________________________________________________________________________ +USE_GREENLETS = False +try: + from py.magic import greenlet +except ImportError: + USE_GREENLETS = False + +if USE_GREENLETS: + runnable_uthreads = {} + uthreads_blocked_on = {} + main_greenlet = greenlet.getcurrent() + + def uthread(space, w_callable, __args__): + def run(): + space.call_args(w_callable, __args__) + gr = greenlet(run) + current = greenlet.getcurrent() + runnable_uthreads[current] = True + gr.switch() + while runnable_uthreads: + next_greenlet, _ = runnable_uthreads.popitem() + if next_greenlet and next_greenlet is not current: + runnable_uthreads[current] = True + next_greenlet.switch() + return space.w_None + app_uthread = gateway.interp2app(uthread, unwrap_spec=[baseobjspace.ObjSpace, + baseobjspace.W_Root, + argument.Arguments]) class W_Var(baseobjspace.W_Root, object): def __init__(w_self): @@ -19,26 +45,40 @@ return w_curr def force(space, w_self): - if not isinstance(w_self, W_Var): - return w_self - w_last = find_last_var_in_chain(w_self) - w_obj = w_last.w_bound_to - if w_obj is None: - # XXX here we would have to suspend the current thread - raise OperationError(space.w_ValueError, - space.wrap("trying to perform an operation on an unbound variable")) - else: - # actually attach the object directly to each variable - # to remove indirections - w_curr = w_self - while 1: - assert isinstance(w_curr, W_Var) - w_next = w_curr.w_bound_to - if not isinstance(w_next, W_Var): - break - w_curr.w_bound_to = w_obj - w_curr = w_next - return w_obj + while 1: + if not isinstance(w_self, W_Var): + return w_self + w_last = find_last_var_in_chain(w_self) + w_obj = w_last.w_bound_to + if w_obj is None: + # XXX here we would have to suspend the current thread + if not USE_GREENLETS: + raise OperationError(space.w_RuntimeError, + space.wrap("trying to perform an operation on an unbound variable")) + else: + current = greenlet.getcurrent() + uthreads_blocked_on.setdefault(w_last, []).append(current) + while runnable_uthreads: + next_greenlet, _ = runnable_uthreads.popitem() + if next_greenlet: + next_greenlet.switch() + # there is a value here now + break + else: + raise OperationError(space.w_RuntimeError, + space.wrap("blocked on variable, but no uthread that can bind it")) + else: + # actually attach the object directly to each variable + # to remove indirections + w_curr = w_self + while 1: + assert isinstance(w_curr, W_Var) + w_next = w_curr.w_bound_to + if not isinstance(w_next, W_Var): + break + w_curr.w_bound_to = w_obj + w_curr = w_next + return w_obj def newvar(space): return W_Var() @@ -74,6 +114,10 @@ w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj w_curr = w_next + if USE_GREENLETS: + now_unblocked_uthreads = uthreads_blocked_on.pop(w_last, []) + for uthread in now_unblocked_uthreads: + runnable_uthreads[uthread] = True return space.w_None app_bind = gateway.interp2app(bind) @@ -203,4 +247,22 @@ space.wrap(app_is_unbound)) space.setitem(space.builtin.w_dict, space.wrap('bind'), space.wrap(app_bind)) + if USE_GREENLETS: + def exitfunc(): + current = greenlet.getcurrent() + while runnable_uthreads: + next_greenlet, _ = runnable_uthreads.popitem() + if next_greenlet and next_greenlet is not current: + runnable_uthreads[current] = True + next_greenlet.switch() + del runnable_uthreads[current] + if uthreads_blocked_on: + print "there are still blocked uthreads!" + for var, blocked in uthreads_blocked_on.iteritems(): + print var, blocked + assert 0 + app_exitfunc = gateway.interp2app(exitfunc, unwrap_spec=[]) + space.setitem(space.sys.w_dict, space.wrap("exitfunc"), space.wrap(app_exitfunc)) + space.setitem(space.builtin.w_dict, space.wrap('uthread'), + space.wrap(app_uthread)) return space Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Thu Mar 9 18:29:28 2006 @@ -47,7 +47,7 @@ X = newvar() def f(x): return x + 1 - raises(ValueError, f, X) + raises(RuntimeError, f, X) def test_bind_to_self(self): X = newvar() From cfbolz at codespeak.net Thu Mar 9 18:35:42 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 18:35:42 +0100 (CET) Subject: [pypy-svn] r24188 - pypy/dist/pypy/objspace Message-ID: <20060309173542.10A251008B@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 18:35:41 2006 New Revision: 24188 Modified: pypy/dist/pypy/objspace/logic.py Log: (pedronis, cfbolz): make it possible to return values from your microthread Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 18:35:41 2006 @@ -14,8 +14,9 @@ main_greenlet = greenlet.getcurrent() def uthread(space, w_callable, __args__): + w_Result = W_Var() def run(): - space.call_args(w_callable, __args__) + space.eq(w_Result, space.call_args(w_callable, __args__)) gr = greenlet(run) current = greenlet.getcurrent() runnable_uthreads[current] = True @@ -25,7 +26,7 @@ if next_greenlet and next_greenlet is not current: runnable_uthreads[current] = True next_greenlet.switch() - return space.w_None + return w_Result app_uthread = gateway.interp2app(uthread, unwrap_spec=[baseobjspace.ObjSpace, baseobjspace.W_Root, argument.Arguments]) From cfbolz at codespeak.net Thu Mar 9 18:40:54 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 18:40:54 +0100 (CET) Subject: [pypy-svn] r24189 - pypy/dist/demo Message-ID: <20060309174054.EEDFA100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 18:40:53 2006 New Revision: 24189 Added: pypy/dist/demo/producerconsumer.py pypy/dist/demo/uthread.py Log: (pedronis, cfbolz): example code that uses the capabilities of the logic object space. they indeed show that using it is not trivial and it is easy to introduce blocked threads for obscure reasons. Added: pypy/dist/demo/producerconsumer.py ============================================================================== --- (empty file) +++ pypy/dist/demo/producerconsumer.py Thu Mar 9 18:40:53 2006 @@ -0,0 +1,31 @@ +"""This is an example that uses the (prototype) Logic Object Space. To run, +you have to set USE_GREENLETS in pypy.objspace.logic to True and do: + + $ py.py -o logic producerconsumer.py + +newvar creates a new unbound logical variable. If you try to access an unbound +variable, the current uthread is blocked, until the variable is bound. +""" + +def generate(n, limit): + print "generate", n, limit + if n < limit: + return (n, generate(n + 1, limit)) + return (None, None) + +def sum(L, a): + print "sum", a + head, Tail = newvar(), newvar() + L == (head, Tail) + if head != None: + return sum(Tail, head + a) + return a + +print "before" +X = newvar() +S = newvar() +S == uthread(sum, X, 0) +X == uthread(generate, 0, 10) +print "after" + +print S Added: pypy/dist/demo/uthread.py ============================================================================== --- (empty file) +++ pypy/dist/demo/uthread.py Thu Mar 9 18:40:53 2006 @@ -0,0 +1,29 @@ +"""This is an example that uses the (prototype) Logic Object Space. To run, +you have to set USE_GREENLETS in pypy.objspace.logic to True and do: + + $ py.py -o logic uthread.py + +newvar creates a new unbound logical variable. If you try to access an unbound +variable, the current uthread is blocked, until the variable is bound. +""" + +X = newvar() +Y = newvar() + +Y == X + +def f(): + print "starting" + print is_unbound(X) + if Y: + print "ok" + return + print "false" + return + +def bind(): + X == 1 + +uthread(f) +print "afterwards" +uthread(bind) From cfbolz at codespeak.net Thu Mar 9 19:01:29 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 19:01:29 +0100 (CET) Subject: [pypy-svn] r24190 - pypy/dist/pypy/objspace Message-ID: <20060309180129.321B3100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 19:01:28 2006 New Revision: 24190 Modified: pypy/dist/pypy/objspace/logic.py Log: rename force to wait Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 19:01:28 2006 @@ -31,6 +31,7 @@ baseobjspace.W_Root, argument.Arguments]) + class W_Var(baseobjspace.W_Root, object): def __init__(w_self): w_self.w_bound_to = None @@ -45,7 +46,7 @@ break return w_curr -def force(space, w_self): +def wait(space, w_self): while 1: if not isinstance(w_self, W_Var): return w_self @@ -168,7 +169,7 @@ if space.is_true(is_unbound(space, w_obj2)): bind(space, w_obj2, w_obj1) return space.w_True - return parentfn(force(space, w_obj1), force(space, w_obj2)) + return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return isoreq def cmpproxy(space, parentfn): @@ -179,7 +180,7 @@ if space.is_true(is_unbound(space, w_obj2)): bind(space, w_obj2, w_obj1) return space.wrap(0) - return parentfn(force(space, w_obj1), force(space, w_obj2)) + return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return cmp def neproxy(space, parentfn): @@ -191,7 +192,7 @@ w_var2 = find_last_var_in_chain(w_obj2) if w_var1 is w_var2: return space.w_False - return parentfn(force(space, w_obj1), force(space, w_obj2)) + return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return ne def is_wproxy(space, parentfn): @@ -202,7 +203,7 @@ if space.is_true(is_unbound(space, w_obj2)): bind(space, w_obj2, w_obj1) return True - return parentfn(force(space, w_obj1), force(space, w_obj2)) + return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return is_w def proxymaker(space, opname, parentfn): @@ -219,18 +220,18 @@ proxy = None elif nb_args == 1: def proxy(w1, *extra): - w1 = force(space, w1) + w1 = wait(space, w1) return parentfn(w1, *extra) elif nb_args == 2: def proxy(w1, w2, *extra): - w1 = force(space, w1) - w2 = force(space, w2) + w1 = wait(space, w1) + w2 = wait(space, w2) return parentfn(w1, w2, *extra) elif nb_args == 3: def proxy(w1, w2, w3, *extra): - w1 = force(space, w1) - w2 = force(space, w2) - w3 = force(space, w3) + w1 = wait(space, w1) + w2 = wait(space, w2) + w3 = wait(space, w3) return parentfn(w1, w2, w3, *extra) else: raise NotImplementedError("operation %r has arity %d" % From cfbolz at codespeak.net Thu Mar 9 19:08:04 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Mar 2006 19:08:04 +0100 (CET) Subject: [pypy-svn] r24191 - pypy/dist/pypy/objspace Message-ID: <20060309180804.16FCB100AA@code0.codespeak.net> Author: cfbolz Date: Thu Mar 9 19:08:02 2006 New Revision: 24191 Modified: pypy/dist/pypy/objspace/logic.py Log: expose wait Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 9 19:08:02 2006 @@ -81,6 +81,7 @@ w_curr.w_bound_to = w_obj w_curr = w_next return w_obj +app_wait = gateway.interp2app(wait) def newvar(space): return W_Var() @@ -267,4 +268,6 @@ space.setitem(space.sys.w_dict, space.wrap("exitfunc"), space.wrap(app_exitfunc)) space.setitem(space.builtin.w_dict, space.wrap('uthread'), space.wrap(app_uthread)) + space.setitem(space.builtin.w_dict, space.wrap('wait'), + space.wrap(app_wait)) return space From ludal at codespeak.net Thu Mar 9 19:32:06 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Thu, 9 Mar 2006 19:32:06 +0100 (CET) Subject: [pypy-svn] r24192 - pypy/dist/pypy/lib/logic/gecode_wrapper Message-ID: <20060309183206.C86D5100AB@code0.codespeak.net> Author: ludal Date: Thu Mar 9 19:32:05 2006 New Revision: 24192 Added: pypy/dist/pypy/lib/logic/gecode_wrapper/ pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h pypy/dist/pypy/lib/logic/gecode_wrapper/main.c pypy/dist/pypy/lib/logic/gecode_wrapper/reine.py pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.cc pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh Log: a sample ctype wrapper for the gecode library Added: pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile Thu Mar 9 19:32:05 2006 @@ -0,0 +1,14 @@ + + +CXXFLAGS=$(shell pkg-config --cflags gecode gecode-minimodel gecode-search) + +LDFLAGS=$(shell pkg-config --libs gecode gecode-minimodel gecode-search) + +reine: main.o libgecode_wrap.so + gcc -o reine -L. -lgecode_wrap main.o + + +libgecode_wrap.so: gecode_wrap.o space_wrap.o gecode_wrap.h space_wrap.hh + g++ -o $@ $(LDFLAGS) -shared $< + + Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc Thu Mar 9 19:32:05 2006 @@ -0,0 +1,58 @@ + +#include "gecode_wrap.h" +#include "space_wrap.hh" + + +void* new_space() +{ + return (void*) new MySpace(); +} + +int new_int_var( void* spc, int is_temp, int _min, int _max ) +{ + MySpace* _spc = static_cast(spc); + return _spc->intVar( is_temp, _min, _max ); +} + +void space_alldiff( void* spc, int n, int* vars ) +{ + MySpace* _spc = static_cast(spc); + _spc->alldiff( vars, vars+n ); +} + +void space_linear( void* spc, int n, int* coefs, int* vars, + int type, int val ) +{ + MySpace* _spc = static_cast(spc); + _spc->linear( coefs, coefs+n, vars, vars+n, (IntRelType)type, val ); +} + +void space_branch( void* spc ) +{ + MySpace* _spc = static_cast(spc); + _spc->branch(); +} + +void* new_dfs( void* spc, int d_c, int d_a ) +{ + MySpace* _spc = static_cast(spc); + return new MyDFSEngine( _spc, d_c, d_a ); +} + +void* search_next( void* search ) +{ + MySearchEngine* _eng = static_cast(search); + return _eng->next(); +} + +void space_values( void* spc, int n, int* vars, int* values ) +{ + MySpace* _spc = static_cast(spc); + _spc->int_values( n, vars, values ); +} + +void space_release( void* spc ) +{ + MySpace* _spc = static_cast(spc); + delete _spc; +} Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h Thu Mar 9 19:32:05 2006 @@ -0,0 +1,32 @@ + +#ifndef GECODE_WRAP_H +#define GECODE_WRAP_H + +#ifdef __cplusplus +extern "C" { +#endif + + void* new_space(); + + int new_int_var( void* spc, int is_temp, int _min, int _max ); + + void space_alldiff( void* spc, int n, int* vars ); + + void space_linear( void* spc, int n, int* coefs, int* vars, + int type, int val ); + + void space_branch( void* spc ); + + void* new_dfs( void* spc, int d_c, int d_a ); + + void* search_next( void* search ); + + void space_values( void* spc, int n, int* vars /*in*/, int* values /*out*/ ); + + void space_release( void* spc ); + +#ifdef __cplusplus +}; +#endif + +#endif Added: pypy/dist/pypy/lib/logic/gecode_wrapper/main.c ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/main.c Thu Mar 9 19:32:05 2006 @@ -0,0 +1,77 @@ +/* -*- c-style: stroustrup -*- + */ + +#include +#include +#include "gecode_wrap.h" + + enum IntRelType { + IRT_EQ, ///< Equality (\f$=\f$) + IRT_NQ, ///< Disequality (\f$\neq\f$) + IRT_LQ, ///< Less or equal (\f$\leq\f$) + IRT_LE, ///< Less (\f$<\f$) + IRT_GQ, ///< Greater or equal (\f$\geq\f$) + IRT_GR ///< Greater (\f$>\f$) + }; + + +int main( int argc, char** argv ) +{ + int coefs[2] = { 1, -1}; + int q[2]; + int n; + void *spc, *engine, *sol; + int* vars, *res; + int i,j; + int nsol = 0; + + if (argc<2) { + printf( "reines N\n" ); + exit(1); + } + n = atoi(argv[1]); + + spc = new_space(); + vars = (int*)malloc(n*sizeof(int)); + res = (int*)malloc(n*sizeof(int)); + + for(i=0;iprint_vars(); + nsol++; + if (nsol%100==0) { + printf("sol:%d\n", nsol ); + space_values( sol, n, vars, res ); + for(j=0;j +#include +#include +#include +#include "kernel.hh" +#include "int.hh" +#include "search.hh" + +#include "space_wrap.hh" + + + + +class MyVar { + virtual MyVar* copy(); +}; +/* +class MyIntVar : public MyVar { +public: + MyIntVar( Space* spc, int _min, int _max ):_var(spc, _min, _max ) {} + MyIntVar( Space* spc, MyIntVar& mvar ):_var( spc, mvar._var ) {} +protected: + IntVar _var; +}; +*/ +enum { + REL_EQ, + REL_NQ, +}; + + +class Index {}; + + + + +void* new_dfs( MySpace* spc, int c_d, int c_a ) +{ + return new MyDFSEngine( spc, c_d, c_a ); +} + +MySpace* search_next( void* _search ) +{ + MySearchEngine* search = static_cast(_search); + return search->next(); +} + + Added: pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh Thu Mar 9 19:32:05 2006 @@ -0,0 +1,118 @@ + + +#ifndef SPACE_WRAP__HH +#define SPACE_WRAP__HH + + +#include +#include +#include +#include +#include "kernel.hh" +#include "int.hh" +#include "search.hh" + +/* + */ +using namespace Gecode; +using namespace std; + +class Unimplemented : public exception {}; + +class MySpace : public Space { +public: + MySpace() {} + + int intVar( bool temp, int _min, int _max ) { + if (!temp) { + _int_vars.push_back( IntVar(this, _min, _max) ); + return _int_vars.size()-1; + } else { + throw Unimplemented(); + } + } + + void alldiff( int* begin, int*end ) + { + IntVarArgs vars( end-begin ); + for(int* i=begin;i!=end;++i) { + vars[i-begin] = _int_vars[*i]; + } + distinct( this, vars ); + } + + void linear( int* cb, int* ce, int* vb, int* ve, IntRelType reltype, int val ) + { + IntArgs c(ce-cb); + IntVarArgs v(ve-vb); + + for(int* i=cb;i!=ce;++i) { + c[i-cb]=*i; + } + for(int* j=vb;j!=ve;++j) { + v[j-vb]=_int_vars[*j]; + } + Gecode::linear(this, c, v, reltype, val ); + } + + void branch() + { + IntVarArgs v(_int_vars.size()); + for(int i=0;i<_int_vars.size();++i) { + v[i] = _int_vars[i]; + } + Gecode::branch(this, v, BVAR_SIZE_MIN, BVAL_MIN); + } + + + void int_values( int n, int* vars, int* values ) + { + for(int i=0;i::iterator its,itd; + for(itd=_int_vars.begin(),its=s._int_vars.begin();itd!=_int_vars.end();++itd,++its) { + itd->update(this, share, *its); + } + } + + /// Perform copying during cloning + virtual Space* copy(bool share) { + return new MySpace(share,*this); + } + + + void print_vars() { + for(int i=0;i<_int_vars.size();++i) + cout << _int_vars[i] << " "; + cout << endl; + } + +protected: + vector< IntVar > _int_vars; + +}; + + +class MySearchEngine { +public: + virtual MySpace* next() = 0; +}; + +class MyDFSEngine : public MySearchEngine { +public: + MyDFSEngine( MySpace* spc, int c_d, int c_a ):dfs(spc,c_d,c_a) {} + virtual MySpace* next() { return dfs.next(); } +protected: + DFS dfs; +}; + +#endif From mwh at codespeak.net Thu Mar 9 20:54:57 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Mar 2006 20:54:57 +0100 (CET) Subject: [pypy-svn] r24194 - in pypy/dist/pypy: rpython/memory translator/c translator/c/src Message-ID: <20060309195457.2EC37100AF@code0.codespeak.net> Author: mwh Date: Thu Mar 9 20:54:55 2006 New Revision: 24194 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/database.py pypy/dist/pypy/translator/c/gc.py pypy/dist/pypy/translator/c/primitive.py pypy/dist/pypy/translator/c/src/g_prerequisite.h Log: so. rip out about half the code i wrote yesterday :) and replace it with a hook into the LowLevelDatabase to ensure the gctransformer gets to see all the roots and their types. we can build standalone stuff now, at last. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 9 20:54:55 2006 @@ -696,6 +696,9 @@ self.gcdata = gcdata self.type_info_list = [] self.id_of_type = {} # {LLTYPE: type_id} + self.seen_roots = {} + self.static_gc_roots = [] + self.addresses_of_static_ptrs_in_nongc = [] self.offsettable_cache = {} self.malloc_fnptr_cache = {} @@ -830,6 +833,18 @@ info["varitemsize"] = llmemory.sizeof(ARRAY.OF) return type_id + def consider_constant(self, TYPE, value): + if id(value) not in self.seen_roots: + self.seen_roots[id(value)] = True + if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)): + self.get_type_id(TYPE) + if TYPE != lltype.PyObject and find_gc_ptrs_in_type(TYPE): + if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)): + self.static_gc_roots.append(value) + else: + for a in gc_pointers_inside(value, llmemory.fakeaddress(value)): + self.addresses_of_static_ptrs_in_nongc.append(a) + def offsets2table(self, offsets): key = tuple(offsets) try: @@ -845,53 +860,6 @@ def finish(self): newgcdependencies = super(FrameworkGCTransformer, self).finish() if self.type_info_list is not None: - # XXX this is a kind of sledgehammer-wallnut approach to make sure - # all types get an ID. - # and to find static roots - # XXX this replicates too much of pypy.rpython.memory.convertlltype :( - seen_types = {} - - def recursive_get_types(t): - if t in seen_types: - return - seen_types[t] = True - if isinstance(t, lltype.Ptr): - recursive_get_types(t.TO) - elif isinstance(t, lltype.Struct): - if isinstance(t, lltype.GcStruct): - self.get_type_id(t) - for n in t._flds: - recursive_get_types(t._flds[n]) - elif isinstance(t, lltype.Array): - if isinstance(t, lltype.GcArray): - self.get_type_id(t) - recursive_get_types(t.OF) - - ll_instance_memo = {} - static_gc_roots = {} - static_roots_inside_nongc = [] - - for graph in self.translator.graphs: - for block in graph.iterblocks(): - for v in block.getvariables(): - t = getattr(v, 'concretetype', None) - if t is None: - continue - recursive_get_types(v.concretetype) - for v in block.getconstants(): - t = getattr(v, 'concretetype', None) - if t is None: - continue - if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \ - find_gc_ptrs_in_type(t.TO): - if t._needsgc(): - static_gc_roots[id(v.value)] = v - else: - for a in gc_pointers_inside(v.value._obj, llmemory.cast_ptr_to_adr(v.value)): - static_roots_inside_nongc.append(a) - for T, inst in lltype.dissect_ll_instance(v.value, t, ll_instance_memo): - if isinstance(T, (lltype.GcArray, lltype.GcStruct)): - self.get_type_id(T) table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) @@ -919,22 +887,20 @@ #self.gcdata.type_info_table = table ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address), - len(static_gc_roots), + len(self.static_gc_roots), immortal=True) - static_roots = static_gc_roots.values() - for i in range(len(static_roots)): - c = static_roots[i] - c_ll_c = rmodel.inputconst(c.concretetype, c.value) - ll_static_roots[i] = llmemory.cast_ptr_to_adr(c_ll_c.value) + for i in range(len(self.static_gc_roots)): + c = self.static_gc_roots[i] + ll_static_roots[i] = llmemory.fakeaddress(c) ll_instance.inst_static_roots = ll_static_roots ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address), - len(static_roots_inside_nongc), + len(self.addresses_of_static_ptrs_in_nongc), immortal=True) - for i in range(len(static_roots_inside_nongc)): - ll_static_roots_inside[i] = static_roots_inside_nongc[i] + for i in range(len(self.addresses_of_static_ptrs_in_nongc)): + ll_static_roots_inside[i] = self.addresses_of_static_ptrs_in_nongc[i] ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address)) - ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(static_roots_inside_nongc) + ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(ll_static_roots_inside) newgcdependencies = newgcdependencies or [] newgcdependencies.append(table) Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Thu Mar 9 20:54:55 2006 @@ -2,6 +2,7 @@ Primitive, Ptr, typeOf, RuntimeTypeInfo, \ Struct, Array, FuncType, PyObject, Void, \ ContainerType, OpaqueType +from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.llmemory import Address from pypy.rpython.memory.lladdress import NULL from pypy.translator.c.primitive import PrimitiveName, PrimitiveType @@ -107,6 +108,9 @@ node = self.containernodes[container] except KeyError: T = typeOf(container) + if isinstance(T, (lltype.Array, lltype.Struct)): + if hasattr(self.gctransformer, 'consider_constant'): + self.gctransformer.consider_constant(T, container) nodefactory = ContainerNodeFactory[T.__class__] node = nodefactory(self, T, container) self.containernodes[container] = node Modified: pypy/dist/pypy/translator/c/gc.py ============================================================================== --- pypy/dist/pypy/translator/c/gc.py (original) +++ pypy/dist/pypy/translator/c/gc.py Thu Mar 9 20:54:55 2006 @@ -280,6 +280,9 @@ fnptr = self.db.gctransformer.frameworkgc_setup_ptr.value yield '%s();' % (self.db.get(fnptr),) + def pre_gc_code(self): + return [] + def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op, err): args = [funcgen.expr(v) for v in op.args] return '%s = %s; /* for moving GCs */' % (args[1], args[0]) Modified: pypy/dist/pypy/translator/c/primitive.py ============================================================================== --- pypy/dist/pypy/translator/c/primitive.py (original) +++ pypy/dist/pypy/translator/c/primitive.py Thu Mar 9 20:54:55 2006 @@ -90,10 +90,18 @@ if value.ob is None: return 'NULL' else: - return db.get(value.ob) + if isinstance(typeOf(value.ob), ContainerType): + return db.getcontainernode(value.ob).ptrname + else: + return db.get(value.ob) else: assert value.offset is not None - return '(void*)(((char*)(%s)) + (%s))'%(db.get(value.ob), db.get(value.offset)) + if isinstance(typeOf(value.ob), ContainerType): + base = db.getcontainernode(value.ob).ptrname + else: + base = db.get(value.ob) + + return '(void*)(((char*)(%s)) + (%s))'%(base, db.get(value.offset)) PrimitiveName = { Signed: name_signed, Modified: pypy/dist/pypy/translator/c/src/g_prerequisite.h ============================================================================== --- pypy/dist/pypy/translator/c/src/g_prerequisite.h (original) +++ pypy/dist/pypy/translator/c/src/g_prerequisite.h Thu Mar 9 20:54:55 2006 @@ -11,3 +11,5 @@ #include "thread.h" /* needs to be included early to define the struct RPyOpaque_ThreadLock */ + +#include From njriley at codespeak.net Thu Mar 9 21:14:27 2006 From: njriley at codespeak.net (njriley at codespeak.net) Date: Thu, 9 Mar 2006 21:14:27 +0100 (CET) Subject: [pypy-svn] r24195 - pypy/branch/njriley-trans/pypy/translator/c/src Message-ID: <20060309201427.23489100AF@code0.codespeak.net> Author: njriley Date: Thu Mar 9 21:14:12 2006 New Revision: 24195 Modified: pypy/branch/njriley-trans/pypy/translator/c/src/g_include.h pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h pypy/branch/njriley-trans/pypy/translator/c/src/mem.h Log: Pause transactions around memory allocation requests (high overhead but conservative for now). Move ll_trans.h earlier in g_include.h because it exports RPyTrans{Pause,Unpause} - lower-level pause/unpause that doesn't use thread-local storage. Modified: pypy/branch/njriley-trans/pypy/translator/c/src/g_include.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/g_include.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/g_include.h Thu Mar 9 21:14:12 2006 @@ -14,6 +14,7 @@ # include "src/standalone.h" #endif +#include "src/ll_trans.h" #include "src/mem.h" #include "src/exception.h" #include "src/trace.h" @@ -40,7 +41,6 @@ # include "src/ll_thread.h" # include "src/ll_stackless.h" # include "src/ll__socket.h" -# include "src/ll_trans.h" # include "src/ll_tsc.h" #endif Modified: pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/ll_trans.h Thu Mar 9 21:14:12 2006 @@ -10,6 +10,8 @@ void LL_trans_verbose(void); void LL_trans_enable(void); void LL_trans_disable(void); +int RPyTransPause(void); +void RPyTransUnpause(int pause_state); /* implementations */ @@ -39,6 +41,20 @@ ; } +int +RPyTransPause(void) +{ + int pause_state; + XACT_PAUSE(pause_state); + return pause_state; +} + +void +RPyTransUnpause(int pause_state) +{ + XACT_UNPAUSE(pause_state); +} + /* XXX deliberately not RPyThreadTLS here => dependency problems */ static pthread_key_t pause_state_key = 0; @@ -78,8 +94,6 @@ LL_trans_enable(void) { int ret_val; - ret_val = enable_transactions(); - assert(ret_val == 0); // XXX HACK HACK HACK, 1024 is first thread id if (pthread_self() == 1024) { static int suspended = 0; @@ -90,6 +104,13 @@ fprintf(stderr, "LL_trans_enable: suspending, pid is %d\n", pid); kill(pid, SIGSTOP); } + ret_val = enable_transactions(); + if (ret_val != 0) { + printf("Load transactional memory module and press return\n"); + while (getchar() != '\n'); + ret_val = enable_transactions(); + assert(ret_val == 0); + } XACT_BEGIN; XACT_PAUSE(ret_val); set_auto_xact(1); @@ -109,7 +130,8 @@ int ret_val; XACT_ACTIVE(ret_val); - assert(ret_val == 0 || ret_val == 1); + if (ret_val != 0 && ret_val != 1) + return 0; return ret_val; } Modified: pypy/branch/njriley-trans/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/mem.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/mem.h Thu Mar 9 21:14:12 2006 @@ -2,7 +2,6 @@ /************************************************************/ /*** C header subsection: operations on LowLevelTypes ***/ - /* a reasonably safe bound on the largest allowed argument value that we can pass to malloc. This is used for var-sized mallocs to compute the largest allowed number of items in the array. */ @@ -69,7 +68,9 @@ /* #define BOEHM_MALLOC_1_1 GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE */ #define OP_BOEHM_ZERO_MALLOC(size, r, is_atomic, is_varsize, err) { \ + int pause_state = RPyTransPause(); \ r = (void*) BOEHM_MALLOC_ ## is_atomic ## _ ## is_varsize (size); \ + RPyTransUnpause(pause_state); \ if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory"); \ if (is_atomic) /* the non-atomic versions return cleared memory */ \ memset((void*) r, 0, size); \ @@ -93,7 +94,9 @@ #undef OP_ZERO_MALLOC #define OP_ZERO_MALLOC(size, r, err) { \ - r = (void*) malloc(size); \ + int pause_state = RPyTransPause(); \ + r = (void*) malloc(size); \ + RPyTransUnpause(pause_state); \ if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ memset((void*) r, 0, size); \ COUNT_MALLOC; \ From njriley at codespeak.net Fri Mar 10 06:12:20 2006 From: njriley at codespeak.net (njriley at codespeak.net) Date: Fri, 10 Mar 2006 06:12:20 +0100 (CET) Subject: [pypy-svn] r24200 - in pypy/branch/njriley-trans: demo lib-python/modified-2.4.1 pypy pypy/annotation pypy/annotation/test pypy/bin pypy/doc pypy/doc/discussion pypy/doc/image pypy/interpreter pypy/interpreter/astcompiler pypy/interpreter/pyparser pypy/interpreter/pyparser/data pypy/interpreter/pyparser/test pypy/interpreter/pyparser/test/samples pypy/interpreter/stablecompiler pypy/interpreter/test pypy/jit pypy/jit/test pypy/lib pypy/lib/logic pypy/lib/logic/computation_space pypy/lib/logic/gecode_wrapper pypy/module/__builtin__ pypy/module/__builtin__/test pypy/module/recparser pypy/module/stackless/test pypy/module/symbol pypy/objspace pypy/objspace/flow pypy/objspace/flow/test pypy/objspace/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/lltypesystem/test pypy/rpython/memory pypy/rpython/ootypesystem pypy/rpython/ootypesystem/test pypy/rpython/rctypes pypy/rpython/rctypes/test pypy/rpython/test pypy/tool pypy/translator pypy/translator/c pypy/translator/c/src pypy/translator/c/test pypy/translator/c/winproj/extension pypy/translator/c/winproj/standalone pypy/translator/goal pypy/translator/llvm pypy/translator/llvm/demo pypy/translator/llvm/pyllvm pypy/translator/llvm/pyllvm/test pypy/translator/llvm/test pypy/translator/squeak pypy/translator/squeak/test pypy/translator/tool Message-ID: <20060310051220.CA8A2100B6@code0.codespeak.net> Author: njriley Date: Fri Mar 10 06:12:02 2006 New Revision: 24200 Added: pypy/branch/njriley-trans/demo/producerconsumer.py - copied unchanged from r24195, pypy/dist/demo/producerconsumer.py pypy/branch/njriley-trans/demo/uthread.py - copied unchanged from r24195, pypy/dist/demo/uthread.py pypy/branch/njriley-trans/lib-python/modified-2.4.1/__future__.py - copied unchanged from r24195, pypy/dist/lib-python/modified-2.4.1/__future__.py pypy/branch/njriley-trans/lib-python/modified-2.4.1/opcode.py - copied unchanged from r24195, pypy/dist/lib-python/modified-2.4.1/opcode.py pypy/branch/njriley-trans/pypy/doc/discussion/removing-stable-compiler.txt - copied unchanged from r24195, pypy/dist/pypy/doc/discussion/removing-stable-compiler.txt pypy/branch/njriley-trans/pypy/doc/discussion/use_case_of_logic.txt - copied unchanged from r24195, pypy/dist/pypy/doc/discussion/use_case_of_logic.txt pypy/branch/njriley-trans/pypy/doc/image/arch-impllevels.graffle - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-impllevels.graffle pypy/branch/njriley-trans/pypy/doc/image/arch-impllevels.pdf - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-impllevels.pdf pypy/branch/njriley-trans/pypy/doc/image/arch-jit-gen.graffle - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-jit-gen.graffle pypy/branch/njriley-trans/pypy/doc/image/arch-jit-gen.pdf - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-jit-gen.pdf pypy/branch/njriley-trans/pypy/doc/image/arch-pypy-basic.graffle - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-pypy-basic.graffle pypy/branch/njriley-trans/pypy/doc/image/arch-pypy-basic.pdf - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-pypy-basic.pdf pypy/branch/njriley-trans/pypy/doc/image/arch-translation.graffle - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-translation.graffle pypy/branch/njriley-trans/pypy/doc/image/arch-translation.pdf - copied unchanged from r24195, pypy/dist/pypy/doc/image/arch-translation.pdf pypy/branch/njriley-trans/pypy/interpreter/pyparser/data/Grammar2.5a - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a pypy/branch/njriley-trans/pypy/interpreter/pyparser/data/Grammar2.5a_with - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a_with pypy/branch/njriley-trans/pypy/interpreter/pyparser/data/Grammar_stablecompiler - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/data/Grammar_stablecompiler pypy/branch/njriley-trans/pypy/interpreter/pyparser/data/README - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/data/README pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/samples/snippet_with_1.py - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_1.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/samples/snippet_with_2.py - copied unchanged from r24195, pypy/dist/pypy/interpreter/pyparser/test/samples/snippet_with_2.py pypy/branch/njriley-trans/pypy/lib/functional.py - copied unchanged from r24195, pypy/dist/pypy/lib/functional.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/event.py - copied unchanged from r24195, pypy/dist/pypy/lib/logic/computation_space/event.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/parsesudoku.py - copied unchanged from r24195, pypy/dist/pypy/lib/logic/computation_space/parsesudoku.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/puzzle1.su - copied unchanged from r24195, pypy/dist/pypy/lib/logic/computation_space/puzzle1.su pypy/branch/njriley-trans/pypy/lib/logic/computation_space/solution.su - copied unchanged from r24195, pypy/dist/pypy/lib/logic/computation_space/solution.su pypy/branch/njriley-trans/pypy/lib/logic/gecode_wrapper/ - copied from r24195, pypy/dist/pypy/lib/logic/gecode_wrapper/ pypy/branch/njriley-trans/pypy/objspace/logic.py - copied unchanged from r24195, pypy/dist/pypy/objspace/logic.py pypy/branch/njriley-trans/pypy/objspace/test/test_logicobjspace.py - copied unchanged from r24195, pypy/dist/pypy/objspace/test/test_logicobjspace.py pypy/branch/njriley-trans/pypy/rpython/exceptiondata.py - copied unchanged from r24195, pypy/dist/pypy/rpython/exceptiondata.py pypy/branch/njriley-trans/pypy/rpython/extregistry.py - copied unchanged from r24195, pypy/dist/pypy/rpython/extregistry.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/exceptiondata.py - copied unchanged from r24195, pypy/dist/pypy/rpython/ootypesystem/exceptiondata.py pypy/branch/njriley-trans/pypy/rpython/rctypes/rarray.py - copied unchanged from r24195, pypy/dist/pypy/rpython/rctypes/rarray.py pypy/branch/njriley-trans/pypy/rpython/rctypes/rprimitive.py - copied unchanged from r24195, pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/branch/njriley-trans/pypy/rpython/rctypes/test/__init__.py - copied unchanged from r24195, pypy/dist/pypy/rpython/rctypes/test/__init__.py pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rarray.py - copied unchanged from r24195, pypy/dist/pypy/rpython/rctypes/test/test_rarray.py pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rprimitive.py - copied unchanged from r24195, pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py pypy/branch/njriley-trans/pypy/rpython/test/test_extregistry.py - copied unchanged from r24195, pypy/dist/pypy/rpython/test/test_extregistry.py pypy/branch/njriley-trans/pypy/tool/__future__.py - copied unchanged from r24195, pypy/dist/pypy/tool/__future__.py pypy/branch/njriley-trans/pypy/translator/goal/targetlogicstandalone.py - copied unchanged from r24195, pypy/dist/pypy/translator/goal/targetlogicstandalone.py pypy/branch/njriley-trans/pypy/translator/llvm/buildllvm.py - copied unchanged from r24195, pypy/dist/pypy/translator/llvm/buildllvm.py pypy/branch/njriley-trans/pypy/translator/llvm/extfunchelper.py - copied unchanged from r24195, pypy/dist/pypy/translator/llvm/extfunchelper.py pypy/branch/njriley-trans/pypy/translator/llvm/pyllvm/ (props changed) - copied from r24195, pypy/dist/pypy/translator/llvm/pyllvm/ pypy/branch/njriley-trans/pypy/translator/llvm/test/test_symbolic.py - copied unchanged from r24195, pypy/dist/pypy/translator/llvm/test/test_symbolic.py pypy/branch/njriley-trans/pypy/translator/squeak/test/support.py - copied unchanged from r24195, pypy/dist/pypy/translator/squeak/test/support.py Removed: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/transformer.py pypy/branch/njriley-trans/pypy/translator/llvm/build_llvm_module.py Modified: pypy/branch/njriley-trans/pypy/annotation/binaryop.py pypy/branch/njriley-trans/pypy/annotation/bookkeeper.py pypy/branch/njriley-trans/pypy/annotation/builtin.py pypy/branch/njriley-trans/pypy/annotation/description.py pypy/branch/njriley-trans/pypy/annotation/model.py pypy/branch/njriley-trans/pypy/annotation/test/test_model.py pypy/branch/njriley-trans/pypy/annotation/unaryop.py pypy/branch/njriley-trans/pypy/bin/py.py pypy/branch/njriley-trans/pypy/conftest.py pypy/branch/njriley-trans/pypy/doc/ctypes-integration.txt pypy/branch/njriley-trans/pypy/doc/events.txt pypy/branch/njriley-trans/pypy/doc/news.txt pypy/branch/njriley-trans/pypy/doc/svn-help.txt pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.py pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.txt pypy/branch/njriley-trans/pypy/interpreter/astcompiler/consts.py pypy/branch/njriley-trans/pypy/interpreter/astcompiler/future.py pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pyassem.py pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pycodegen.py pypy/branch/njriley-trans/pypy/interpreter/gateway.py pypy/branch/njriley-trans/pypy/interpreter/pycompiler.py pypy/branch/njriley-trans/pypy/interpreter/pyopcode.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/astbuilder.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/ebnfparse.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/pysymbol.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonparse.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonutil.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/symbol.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astbuilder.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astcompiler.py pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_samples.py pypy/branch/njriley-trans/pypy/interpreter/stablecompiler/transformer.py pypy/branch/njriley-trans/pypy/interpreter/test/test_syntax.py pypy/branch/njriley-trans/pypy/jit/hintrtyper.py pypy/branch/njriley-trans/pypy/jit/hinttimeshift.py pypy/branch/njriley-trans/pypy/jit/rtimeshift.py pypy/branch/njriley-trans/pypy/jit/test/test_hint_annotation.py pypy/branch/njriley-trans/pypy/jit/test/test_hint_timeshift.py pypy/branch/njriley-trans/pypy/jit/test/test_llabstractinterp.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/computationspace.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/constraint.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/distributor.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/problems.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/state.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/strategies.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_computationspace.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_variable.py pypy/branch/njriley-trans/pypy/lib/logic/computation_space/variable.py pypy/branch/njriley-trans/pypy/lib/logic/oz-dataflow-concurrency.txt pypy/branch/njriley-trans/pypy/module/__builtin__/__init__.py pypy/branch/njriley-trans/pypy/module/__builtin__/app_functional.py pypy/branch/njriley-trans/pypy/module/__builtin__/test/test_functional.py pypy/branch/njriley-trans/pypy/module/recparser/pyparser.py pypy/branch/njriley-trans/pypy/module/stackless/test/test_interp_coroutine.py pypy/branch/njriley-trans/pypy/module/symbol/__init__.py pypy/branch/njriley-trans/pypy/objspace/flow/model.py pypy/branch/njriley-trans/pypy/objspace/flow/objspace.py pypy/branch/njriley-trans/pypy/objspace/flow/test/test_objspace.py pypy/branch/njriley-trans/pypy/rpython/callparse.py pypy/branch/njriley-trans/pypy/rpython/llinterp.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/exceptiondata.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/llmemory.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/lloperation.py (props changed) pypy/branch/njriley-trans/pypy/rpython/lltypesystem/lltype.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rclass.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rpbc.py pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lloperation.py (contents, props changed) pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lltype.py pypy/branch/njriley-trans/pypy/rpython/memory/gc.py pypy/branch/njriley-trans/pypy/rpython/memory/gctransform.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/ootype.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rbuiltin.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rclass.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rpbc.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ooann.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oopbc.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oortype.py pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ootype.py pypy/branch/njriley-trans/pypy/rpython/rbuiltin.py pypy/branch/njriley-trans/pypy/rpython/rclass.py pypy/branch/njriley-trans/pypy/rpython/rctypes/implementation.py pypy/branch/njriley-trans/pypy/rpython/rctypes/interface.py pypy/branch/njriley-trans/pypy/rpython/rctypes/test/ (props changed) pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rctypes.py pypy/branch/njriley-trans/pypy/rpython/rgenop.py pypy/branch/njriley-trans/pypy/rpython/rmodel.py pypy/branch/njriley-trans/pypy/rpython/rpbc.py pypy/branch/njriley-trans/pypy/rpython/rtyper.py pypy/branch/njriley-trans/pypy/rpython/test/test_llinterp.py pypy/branch/njriley-trans/pypy/rpython/test/test_ootype_llinterp.py pypy/branch/njriley-trans/pypy/rpython/test/test_rclass.py pypy/branch/njriley-trans/pypy/rpython/test/test_rgenop.py pypy/branch/njriley-trans/pypy/rpython/test/test_rpbc.py pypy/branch/njriley-trans/pypy/rpython/typesystem.py pypy/branch/njriley-trans/pypy/tool/isolate.py pypy/branch/njriley-trans/pypy/tool/opcode.py pypy/branch/njriley-trans/pypy/tool/option.py pypy/branch/njriley-trans/pypy/translator/c/database.py pypy/branch/njriley-trans/pypy/translator/c/external.py pypy/branch/njriley-trans/pypy/translator/c/funcgen.py pypy/branch/njriley-trans/pypy/translator/c/gc.py pypy/branch/njriley-trans/pypy/translator/c/genc.py pypy/branch/njriley-trans/pypy/translator/c/node.py pypy/branch/njriley-trans/pypy/translator/c/primitive.py pypy/branch/njriley-trans/pypy/translator/c/src/address.h pypy/branch/njriley-trans/pypy/translator/c/src/g_prerequisite.h pypy/branch/njriley-trans/pypy/translator/c/src/support.h pypy/branch/njriley-trans/pypy/translator/c/stackless.py pypy/branch/njriley-trans/pypy/translator/c/symboltable.py pypy/branch/njriley-trans/pypy/translator/c/test/test_boehm.py pypy/branch/njriley-trans/pypy/translator/c/test/test_genc.py pypy/branch/njriley-trans/pypy/translator/c/test/test_newgc.py pypy/branch/njriley-trans/pypy/translator/c/test/test_symbolic.py (contents, props changed) pypy/branch/njriley-trans/pypy/translator/c/winproj/extension/extension.vcproj pypy/branch/njriley-trans/pypy/translator/c/winproj/standalone/standalone.vcproj pypy/branch/njriley-trans/pypy/translator/driver.py pypy/branch/njriley-trans/pypy/translator/geninterplevel.py pypy/branch/njriley-trans/pypy/translator/gensupp.py pypy/branch/njriley-trans/pypy/translator/goal/translate.py pypy/branch/njriley-trans/pypy/translator/interactive.py pypy/branch/njriley-trans/pypy/translator/llvm/codewriter.py pypy/branch/njriley-trans/pypy/translator/llvm/database.py pypy/branch/njriley-trans/pypy/translator/llvm/demo/bpnn.py pypy/branch/njriley-trans/pypy/translator/llvm/demo/run.py pypy/branch/njriley-trans/pypy/translator/llvm/externs2ll.py pypy/branch/njriley-trans/pypy/translator/llvm/genllvm.py pypy/branch/njriley-trans/pypy/translator/llvm/opwriter.py pypy/branch/njriley-trans/pypy/translator/llvm/pyllvm/test/ (props changed) pypy/branch/njriley-trans/pypy/translator/llvm/structnode.py pypy/branch/njriley-trans/pypy/translator/llvm/test/runtest.py pypy/branch/njriley-trans/pypy/translator/squeak/gensqueak.py pypy/branch/njriley-trans/pypy/translator/squeak/test/test_oo.py pypy/branch/njriley-trans/pypy/translator/squeak/test/test_squeaktrans.py pypy/branch/njriley-trans/pypy/translator/tool/cbuild.py pypy/branch/njriley-trans/pypy/translator/tool/graphpage.py pypy/branch/njriley-trans/pypy/translator/tool/make_dot.py pypy/branch/njriley-trans/pypy/translator/translator.py Log: merged to trunk r24194 Modified: pypy/branch/njriley-trans/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/binaryop.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/binaryop.py Fri Mar 10 06:12:02 2006 @@ -16,9 +16,11 @@ from pypy.annotation.model import SomeCTypesObject from pypy.annotation.model import unionof, UnionError, set, missing_operation, TLS from pypy.annotation.model import add_knowntypedata, merge_knowntypedata +from pypy.annotation.model import lltype_to_annotation from pypy.annotation.bookkeeper import getbookkeeper from pypy.objspace.flow.model import Variable from pypy.annotation.listdef import ListDef +from pypy.rpython import extregistry # convenience only! def immutablevalue(x): @@ -761,6 +763,10 @@ # are those having memorystate NOMEMORY return s_cto.knowntype._type_.annotator_type except AttributeError: + if extregistry.is_registered_type(s_cto.knowntype._type_): + entry = extregistry.lookup_type(s_cto.knowntype._type_) + return lltype_to_annotation(entry.lowleveltype) + return SomeCTypesObject( s_cto.knowntype._type_, memorystate=s_cto.memorystate) Modified: pypy/branch/njriley-trans/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/bookkeeper.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/bookkeeper.py Fri Mar 10 06:12:02 2006 @@ -23,6 +23,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.ootypesystem import ootype from pypy.rpython.memory import lladdress +from pypy.rpython import extregistry class Stats: @@ -358,6 +359,8 @@ elif ishashable(x) and x in BUILTIN_ANALYZERS: _module = getattr(x,"__module__","unknown") result = SomeBuiltin(BUILTIN_ANALYZERS[x], methodname="%s.%s" % (_module, x.__name__)) + elif extregistry.is_registered(x): + result = extregistry.lookup(x).get_annotation(tp, x) elif hasattr(x, "compute_result_annotation"): result = SomeBuiltin(x.compute_result_annotation, methodname=x.__name__) elif hasattr(tp, "compute_annotation"): @@ -511,6 +514,8 @@ return SomeExternalObject(t) elif hasattr(t, "compute_annotation"): return t.compute_annotation() + elif extregistry.is_registered_type(t): + return extregistry.lookup_type(t).get_annotation(t) elif t.__module__ != '__builtin__' and t not in self.pbctypes: classdef = self.getuniqueclassdef(t) return SomeInstance(classdef) Modified: pypy/branch/njriley-trans/pypy/annotation/builtin.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/builtin.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/builtin.py Fri Mar 10 06:12:02 2006 @@ -464,6 +464,11 @@ assert isinstance(i, SomeOOInstance) return SomeOOClass(i.ootype) +def subclassof(class1, class2): + assert isinstance(class1, SomeOOClass) + assert isinstance(class2, SomeOOClass) + return SomeBool() + def runtimenew(c): assert isinstance(c, SomeOOClass) if c.ootype is None: @@ -480,6 +485,7 @@ BUILTIN_ANALYZERS[ootype.null] = null BUILTIN_ANALYZERS[ootype.runtimenew] = runtimenew BUILTIN_ANALYZERS[ootype.classof] = classof +BUILTIN_ANALYZERS[ootype.subclassof] = subclassof BUILTIN_ANALYZERS[ootype.ooidentityhash] = ooidentityhash #________________________________ Modified: pypy/branch/njriley-trans/pypy/annotation/description.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/description.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/description.py Fri Mar 10 06:12:02 2006 @@ -398,7 +398,7 @@ from pypy.annotation.model import s_None, SomeInstance s_func = self.s_read_attribute('__del__') args_s = [SomeInstance(classdef)] - s = self.bookkeeper.emulate_pbc_call(None, s_func, args_s) + s = self.bookkeeper.emulate_pbc_call(classdef, s_func, args_s) assert s_None.contains(s) return classdef Modified: pypy/branch/njriley-trans/pypy/annotation/model.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/model.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/model.py Fri Mar 10 06:12:02 2006 @@ -565,6 +565,8 @@ return SomeOOInstance(T) elif isinstance(T, ootype.StaticMethod): return SomeOOStaticMeth(T) + elif T == ootype.Class: + return SomeOOClass(ootype.ROOT) else: return SomePtr(T) else: Modified: pypy/branch/njriley-trans/pypy/annotation/test/test_model.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/test/test_model.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/test/test_model.py Fri Mar 10 06:12:02 2006 @@ -3,6 +3,7 @@ import py from pypy.annotation.model import * from pypy.annotation.listdef import ListDef, MOST_GENERAL_LISTDEF +from pypy.rpython.ootypesystem.ootype import ROOT listdef1 = ListDef(None, SomeTuple([SomeInteger(nonneg=True), SomeString()])) @@ -118,7 +119,7 @@ assert isinstance(s_p, SomePtr) and s_p.ll_ptrtype == lltype.Ptr(S) s_p = ll_to_annotation(lltype.malloc(A, 0)) assert isinstance(s_p, SomePtr) and s_p.ll_ptrtype == lltype.Ptr(A) - C = ootype.Instance('C', None, {}) + C = ootype.Instance('C', ROOT, {}) s_p = ll_to_annotation(ootype.new(C)) assert isinstance(s_p, SomeOOInstance) and s_p.ootype == C @@ -143,7 +144,7 @@ s_p = SomePtr(ll_ptrtype=PS) assert annotation_to_lltype(s_p) == PS py.test.raises(ValueError, "annotation_to_lltype(si0)") - C = ootype.Instance('C', None, {}) + C = ootype.Instance('C', ROOT, {}) ref = SomeOOInstance(C) assert annotation_to_lltype(ref) == C @@ -173,10 +174,10 @@ py.test.raises(AssertionError, "unionof(SomeObject(), SomePtr(PS1))") def test_oo_union(): - C1 = ootype.Instance("C1", None) + C1 = ootype.Instance("C1", ROOT) C2 = ootype.Instance("C2", C1) C3 = ootype.Instance("C3", C1) - D = ootype.Instance("D", None) + D = ootype.Instance("D", ROOT) assert unionof(SomeOOInstance(C1), SomeOOInstance(C1)) == SomeOOInstance(C1) assert unionof(SomeOOInstance(C1), SomeOOInstance(C2)) == SomeOOInstance(C1) assert unionof(SomeOOInstance(C2), SomeOOInstance(C1)) == SomeOOInstance(C1) @@ -185,12 +186,7 @@ assert unionof(SomeOOInstance(C1),SomeImpossibleValue()) == SomeOOInstance(C1) assert unionof(SomeImpossibleValue(), SomeOOInstance(C1)) == SomeOOInstance(C1) - py.test.raises(AssertionError, "unionof(SomeOOInstance(C1), SomeOOInstance(D))") - py.test.raises(AssertionError, "unionof(SomeOOInstance(D), SomeOOInstance(C1))") - py.test.raises(AssertionError, "unionof(SomeOOInstance(C1), SomeInteger())") - py.test.raises(AssertionError, "unionof(SomeInteger(), SomeOOInstance(C1))") - py.test.raises(AssertionError, "unionof(SomeOOInstance(C1), SomeObject())") - py.test.raises(AssertionError, "unionof(SomeObject(), SomeOOInstance(C1))") + assert unionof(SomeOOInstance(C1), SomeOOInstance(D)) == SomeOOInstance(ROOT) if __name__ == '__main__': for name, value in globals().items(): Modified: pypy/branch/njriley-trans/pypy/annotation/unaryop.py ============================================================================== --- pypy/branch/njriley-trans/pypy/annotation/unaryop.py (original) +++ pypy/branch/njriley-trans/pypy/annotation/unaryop.py Fri Mar 10 06:12:02 2006 @@ -13,6 +13,7 @@ from pypy.annotation import builtin from pypy.annotation.binaryop import _clone ## XXX where to put this? +from pypy.rpython import extregistry # convenience only! def immutablevalue(x): @@ -644,7 +645,12 @@ "%r object has no attribute %r" % ( cto.knowntype, s_attr.const)) else: - atype = cto.knowntype._fields_def_[attr] + if extregistry.is_registered_type(cto.knowntype): + entry = extregistry.lookup_type(cto.knowntype) + s_value = entry.fields_s[attr] + return s_value + else: + atype = cto.knowntype._fields_def_[attr] try: return atype.annotator_type except AttributeError: Modified: pypy/branch/njriley-trans/pypy/bin/py.py ============================================================================== --- pypy/branch/njriley-trans/pypy/bin/py.py (original) +++ pypy/branch/njriley-trans/pypy/bin/py.py Fri Mar 10 06:12:02 2006 @@ -58,6 +58,8 @@ from pypy.objspace.std import Space elif cmdlineopt.objspace == 'thunk': from pypy.objspace.thunk import Space + elif cmdlineopt.objspace == 'logic': + from pypy.objspace.logic import Space else: raise ValueError("cannot instantiate %r space" %(cmdlineopt.objspace,)) Modified: pypy/branch/njriley-trans/pypy/conftest.py ============================================================================== --- pypy/branch/njriley-trans/pypy/conftest.py (original) +++ pypy/branch/njriley-trans/pypy/conftest.py Fri Mar 10 06:12:02 2006 @@ -54,7 +54,7 @@ try: return _SPACECACHE[key] except KeyError: - assert name in ('std', 'thunk'), name + assert name in ('std', 'thunk', 'logic'), name mod = __import__('pypy.objspace.%s' % name, None, None, ['Space']) Space = mod.Space try: Modified: pypy/branch/njriley-trans/pypy/doc/ctypes-integration.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/doc/ctypes-integration.txt (original) +++ pypy/branch/njriley-trans/pypy/doc/ctypes-integration.txt Fri Mar 10 06:12:02 2006 @@ -80,46 +80,116 @@ Memory-Layout ------------- +In Ctypes, all instances are mutable boxes containing either some raw +memory with a layout compatible to that of the equivalent C type, or a +reference to such memory. The reference indirection is transparent to +the user; for example, dereferencing a ctypes object "pointer to +structure" results in a "structure" object that doesn't include a copy +of the data, but only a reference to that data. (This is similar to the +C++ notion of reference: it is just a pointer at the machine level, but +at the language level it behaves like the object that it points to, not +like a pointer.) + +We map this to the LLType model as follows. For boxes that embed the +raw memory content:: + + Ptr( GcStruct( "name", + ("c_data", Struct(...) ) ) ) + +where the raw memory content and layout is specified by the +"Struct(...)" part. + +For boxes that don't embed the raw memory content:: + + Ptr( GcStruct( "name", + ("c_data_ref", Ptr(Struct(...)) ) ) ) + +In both cases, the outer GcStruct is needed to make the boxes tracked by +the GC automatically. The "c_data" or "c_data_ref" field either embeds +or references the raw memory; the "Struct(...)" definition specifies the +exact C layout expected for that memory. + +Of course, the "c_data" and "c_data_ref" fields are not visible to the +rpython-level user. This is where an rctype-specific restriction comes +from: it must be possible for the annotator to figure out statically for +each variable if it needs to be implemented with a "c_data" or a +"c_data_ref" field. (The annotation SomeCTypesObject contains a +memorystate field which can be OWNSMEMORY ("c_data" case) or MEMORYALIAS +("c_data_ref" case).) + Primitive Types ~~~~~~~~~~~~~~~ +Ctypes' primitive types are mapped directly to the correspondending PyPy +LLType: Signed, Float, etc. For the owned-memory case, we get:: -Ctypes' primitive types are mapped directly to the correspondending -PyPy type. - -Structures -~~~~~~~~~~ -Structures will have the following memory layout if they were allocated by ctypes:: - - Ptr( GcStruct( "CtypesGcStructure_ - ( "c_data" - (Struct "C-Data_ - *) ) ) ) - -We will try hard not to expose the "c-data" member of the structure -at rpython level. - -Structures that result form dereferencing a pointer will have the following -layout:: - - Ptr( GcStruct( "CtypesStructure_ - ( "c_data" - Ptr( Struct( "C-Data_ - *) ) ) ) ) + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Signed/Float/etc. ) ) ) ) ) + +Note that we don't make "c_data" itself a Signed or Float directly because +in LLType we can't take pointers to Signed or Float, only to Struct or +Array. + +The non-owned-memory case is:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + ( "value", Signed/Float/etc. ) ) ) ) ) ) Pointers ~~~~~~~~ -Pointers pointing to structures allocated by ctypes will have the following memory layout:: - Ptr( GcStruct( "CtypesGCPointer_ - "contents" Ptr( GcStruct( "CtypesGcStructure_" ... ) ) ) ) +:: + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Ptr(...) ) ) ) ) ) + +or:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + ( "value", Ptr(...) ) ) ) ) ) ) + +However, there is a special case here: the pointer might point to data +owned by another CtypesBox -- i.e. it can point to the "c_data" field of +some other CtypesBox. In this case we must make sure that the other +CtypesBox stays alive. This is done by adding an extra field +referencing the gc box (this field is not otherwise used):: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + ( "value", Ptr(...) ) ) ) + ( "keepalive" + (Ptr(GcStruct("CtypesBox_"))) ) ) ) -Pointers pointing returned from external functions have the follwing layout if the -point to a structure:: +Structures +~~~~~~~~~~ +Structures will have the following memory layout (owning their raw memory) +if they were allocated by ctypes:: + + Ptr( GcStruct( "CtypesBox_ + ( "c_data" + (Struct "C_Data_ + *) ) ) ) - Ptr( GcStruct( "CtypesPointer_" - "contents" Ptr( Struct( "CtypesStructure_" ... ) ) ) ) +For structures obtained by dereferencing a pointer (by reading its +"contents" attribute), the structure box does not own the memory:: -Currently it is not decided whether assiging a pointers `contents` attribute from -a GC-pointer should be allowed. The other case will only become valid if we implement -structures with mixed memory state. + Ptr( GcStruct( "CtypesBox_ + ( "c_data_ref" + (Ptr(Struct "C_Data_ + *) ) ) ) ) + +One or several Keepalive fields might be necessary in each case. +(To be clarified...) + +Arrays +~~~~~~ +Arrays behave like structures, but use an Array instead of a Struct in +the "c_data" or "c_data_ref" declaration. Modified: pypy/branch/njriley-trans/pypy/doc/events.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/doc/events.txt (original) +++ pypy/branch/njriley-trans/pypy/doc/events.txt Fri Mar 10 06:12:02 2006 @@ -7,26 +7,6 @@ .. _`over there`: webcal://pypycal.sabi.net///calendars/PyPy.ics -Talks at PyCon 2006 (Dallas, Texas, USA) -=================================================================== - -*Feb 24th - Feb 26th 2006.* PyPy developers will speak at `PyCon 2006`_. - -.. _`PyCon 2006`: http://us.pycon.org/TX2006/HomePage - -PyCon Sprint 2006 (Dallas, Texas, USA) -================================================================== - -*Feb 27th - March 2nd 2006.* The Post-PyCon PyPy Sprint is scheduled to -take place right after PyCon 2006. - -We hope to see lots of newcomers at this sprint, so we'll give -friendly introductions. Note that during the Pycon conference we are -giving PyPy talks which serve well as preparation. Read more in the -`announcement`_. - -.. _`announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/pycon06/sprint-announcement.html - Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) ======================================================================== Modified: pypy/branch/njriley-trans/pypy/doc/news.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/doc/news.txt (original) +++ pypy/branch/njriley-trans/pypy/doc/news.txt Fri Mar 10 06:12:02 2006 @@ -7,6 +7,23 @@ .. _Python: http://www.python.org/doc/current/ref/ref.html .. _`more...`: http://codespeak.net/pypy/dist/pypy/doc/architecture.html#mission-statement +PyCon Sprint 2006 (Dallas, Texas, USA) +================================================================== + +*Feb 27th - March 2nd 2006.* The Post-PyCon PyPy Sprint took place +right after PyCon 2006. + +A report is coming up. + + +Talks at PyCon 2006 (Dallas, Texas, USA) +=================================================================== + +*Feb 24th - Feb 26th 2006.* PyPy developers spoke at `PyCon 2006`_. + +.. _`PyCon 2006`: http://us.pycon.org/TX2006/HomePage + + PyPy at Solutions Linux in Paris January 31st - February 2nd 2006 =================================================================== Modified: pypy/branch/njriley-trans/pypy/doc/svn-help.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/doc/svn-help.txt (original) +++ pypy/branch/njriley-trans/pypy/doc/svn-help.txt Fri Mar 10 06:12:02 2006 @@ -120,6 +120,9 @@ http: in the subversion URL. This will make use of SSL encryption, which cannot be intercepted by proxies. +Alternatively, if you want to change your proxy configuration, see the +subversion FAQ: http://subversion.tigris.org/faq.html#proxy + How to Avoid Line-ending Hell ----------------------------- Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.py Fri Mar 10 06:12:02 2006 @@ -1232,6 +1232,63 @@ ops=GetSetProperty(Compare.fget_ops, Compare.fset_ops ), ) +class CondExpr(Node): + def __init__(self, test, true_expr, false_expr, lineno=-1): + Node.__init__(self, lineno) + self.test = test + self.true_expr = true_expr + self.false_expr = false_expr + + def getChildren(self): + "NOT_RPYTHON" + return self.test, self.true_expr, self.false_expr + + def getChildNodes(self): + return [self.test, self.true_expr, self.false_expr] + + def __repr__(self): + return "CondExpr(%s, %s, %s)" % (self.test.__repr__(), self.true_expr.__repr__(), self.false_expr.__repr__()) + + def accept(self, visitor): + return visitor.visitCondExpr(self) + + def fget_test( space, self): + return space.wrap(self.test) + def fset_test( space, self, w_arg): + self.test = space.interp_w(Node, w_arg, can_be_None=False) + def fget_true_expr( space, self): + return space.wrap(self.true_expr) + def fset_true_expr( space, self, w_arg): + self.true_expr = space.interp_w(Node, w_arg, can_be_None=False) + def fget_false_expr( space, self): + return space.wrap(self.false_expr) + def fset_false_expr( space, self, w_arg): + self.false_expr = space.interp_w(Node, w_arg, can_be_None=False) + +def descr_CondExpr_new(space, w_subtype, w_test, w_true_expr, w_false_expr, lineno=-1): + self = space.allocate_instance(CondExpr, w_subtype) + test = space.interp_w(Node, w_test, can_be_None=False) + self.test = test + true_expr = space.interp_w(Node, w_true_expr, can_be_None=False) + self.true_expr = true_expr + false_expr = space.interp_w(Node, w_false_expr, can_be_None=False) + self.false_expr = false_expr + self.lineno = lineno + return space.wrap(self) + +def descr_CondExpr_accept( space, w_self, w_visitor): + w_callable = space.getattr(w_visitor, space.wrap('visitCondExpr')) + args = Arguments(space, [ w_self ]) + return space.call_args(w_callable, args) + +CondExpr.typedef = TypeDef('CondExpr', Node.typedef, + __new__ = interp2app(descr_CondExpr_new, unwrap_spec=[ObjSpace, W_Root, W_Root, W_Root, W_Root, int]), + accept=interp2app(descr_CondExpr_accept, unwrap_spec=[ObjSpace, W_Root, W_Root] ), + test=GetSetProperty(CondExpr.fget_test, CondExpr.fset_test ), + true_expr=GetSetProperty(CondExpr.fget_true_expr, CondExpr.fset_true_expr ), + false_expr=GetSetProperty(CondExpr.fget_false_expr, CondExpr.fset_false_expr ), + ) + class Const(Node): def __init__(self, value, lineno=-1): Node.__init__(self, lineno) @@ -4129,6 +4186,75 @@ else_=GetSetProperty(While.fget_else_, While.fset_else_ ), ) +class With(Node): + def __init__(self, expr, body, var, lineno=-1): + Node.__init__(self, lineno) + self.expr = expr + self.body = body + self.var = var + + def getChildren(self): + "NOT_RPYTHON" + children = [] + children.append(self.expr) + children.append(self.body) + children.append(self.var) + return tuple(children) + + def getChildNodes(self): + nodelist = [] + nodelist.append(self.expr) + nodelist.append(self.body) + if self.var is not None: + nodelist.append(self.var) + return nodelist + + def __repr__(self): + return "With(%s, %s, %s)" % (self.expr.__repr__(), self.body.__repr__(), self.var.__repr__()) + + def accept(self, visitor): + return visitor.visitWith(self) + + def fget_expr( space, self): + return space.wrap(self.expr) + def fset_expr( space, self, w_arg): + self.expr = space.interp_w(Node, w_arg, can_be_None=False) + def fget_body( space, self): + return space.wrap(self.body) + def fset_body( space, self, w_arg): + self.body = space.interp_w(Node, w_arg, can_be_None=False) + def fget_var( space, self): + if self.var is None: + return space.w_None + else: + return space.wrap(self.var) + def fset_var( space, self, w_arg): + self.var = space.interp_w(Node, w_arg, can_be_None=True) + +def descr_With_new(space, w_subtype, w_expr, w_body, w_var, lineno=-1): + self = space.allocate_instance(With, w_subtype) + expr = space.interp_w(Node, w_expr, can_be_None=False) + self.expr = expr + body = space.interp_w(Node, w_body, can_be_None=False) + self.body = body + var = space.interp_w(Node, w_var, can_be_None=True) + self.var = var + self.lineno = lineno + return space.wrap(self) + +def descr_With_accept( space, w_self, w_visitor): + w_callable = space.getattr(w_visitor, space.wrap('visitWith')) + args = Arguments(space, [ w_self ]) + return space.call_args(w_callable, args) + +With.typedef = TypeDef('With', Node.typedef, + __new__ = interp2app(descr_With_new, unwrap_spec=[ObjSpace, W_Root, W_Root, W_Root, W_Root, int]), + accept=interp2app(descr_With_accept, unwrap_spec=[ObjSpace, W_Root, W_Root] ), + expr=GetSetProperty(With.fget_expr, With.fset_expr ), + body=GetSetProperty(With.fget_body, With.fset_body ), + var=GetSetProperty(With.fget_var, With.fset_var ), + ) + class Yield(Node): def __init__(self, value, lineno=-1): Node.__init__(self, lineno) @@ -4232,6 +4358,8 @@ return self.default( node ) def visitCompare(self, node): return self.default( node ) + def visitCondExpr(self, node): + return self.default( node ) def visitConst(self, node): return self.default( node ) def visitContinue(self, node): @@ -4340,6 +4468,8 @@ return self.default( node ) def visitWhile(self, node): return self.default( node ) + def visitWith(self, node): + return self.default( node ) def visitYield(self, node): return self.default( node ) Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.txt (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/ast.txt Fri Mar 10 06:12:02 2006 @@ -27,6 +27,7 @@ Break: Continue: For: assign, list, body, else_& +With: expr, body, var& While: test, body, else_& If: tests!, else_& Exec: expr, locals&, globals& @@ -78,6 +79,7 @@ AbstractTest: Or(AbstractTest): nodes! And(AbstractTest): nodes! +CondExpr: test, true_expr, false_expr BitOp: Bitor(BitOp): nodes! Bitxor(BitOp): nodes! Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/consts.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/consts.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/consts.py Fri Mar 10 06:12:02 2006 @@ -19,3 +19,4 @@ CO_GENERATOR = 0x0020 CO_GENERATOR_ALLOWED = 0x1000 CO_FUTURE_DIVISION = 0x2000 +CO_FUTURE_WITH_STATEMENT = 0x8000 Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/future.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/future.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/future.py Fri Mar 10 06:12:02 2006 @@ -15,7 +15,7 @@ class FutureParser(ast.ASTVisitor): - features = ("nested_scopes", "generators", "division") + features = ("nested_scopes", "generators", "division", "with_statement") def __init__(self): self.found = {} # set Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pyassem.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pyassem.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pyassem.py Fri Mar 10 06:12:02 2006 @@ -1,6 +1,5 @@ """A flow graph representation for Python bytecode""" -import dis import sys from pypy.interpreter.astcompiler import misc, ast @@ -8,8 +7,7 @@ import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS from pypy.interpreter.pycode import PyCode from pypy.interpreter.baseobjspace import W_Root - - +from pypy.tool import opcode as pythonopcode class BlockSet: """A Set implementation specific to Blocks @@ -633,11 +631,11 @@ self.stage = FLAT hasjrel = {} - for i in dis.hasjrel: - hasjrel[dis.opname[i]] = True + for i in pythonopcode.hasjrel: + hasjrel[pythonopcode.opname[i]] = True hasjabs = {} - for i in dis.hasjabs: - hasjabs[dis.opname[i]] = True + for i in pythonopcode.hasjabs: + hasjabs[pythonopcode.opname[i]] = True def convertArgs(self): """Convert arguments from symbolic to concrete form""" @@ -772,7 +770,7 @@ index = self._lookupName(arg, self.closure) return InstrInt(inst.op, index) - _cmp = list(dis.cmp_op) + _cmp = list(pythonopcode.cmp_op) def _convert_COMPARE_OP(self, inst): assert isinstance(inst, InstrName) arg = inst.name @@ -817,8 +815,9 @@ self.stage = DONE opnum = {} - for num in range(len(dis.opname)): - opnum[dis.opname[num]] = num + for num in range(len(pythonopcode.opname)): + opnum[pythonopcode.opname[num]] = num + # This seems to duplicate dis.opmap from opcode.opmap del num def newCodeObject(self): @@ -1048,6 +1047,7 @@ 'SETUP_EXCEPT': 3, 'SETUP_FINALLY': 3, 'FOR_ITER': 1, + 'WITH_CLEANUP': 3, } # use pattern match patterns = [ Modified: pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/astcompiler/pycodegen.py Fri Mar 10 06:12:02 2006 @@ -10,7 +10,8 @@ from pypy.interpreter.astcompiler.consts import SC_LOCAL, SC_GLOBAL, \ SC_FREE, SC_CELL, SC_DEFAULT, OP_APPLY, OP_ASSIGN, OP_DELETE, OP_NONE from pypy.interpreter.astcompiler.consts import CO_VARARGS, CO_VARKEYWORDS, \ - CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION + CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, \ + CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT from pypy.interpreter.pyparser.error import SyntaxError # drop VERSION dependency since it the ast transformer for 2.4 doesn't work with 2.3 anyway @@ -164,6 +165,8 @@ self._div_op = "BINARY_TRUE_DIVIDE" elif feature == "generators": self.graph.setFlag(CO_GENERATOR_ALLOWED) + elif feature == "with_statement": + self.graph.setFlag(CO_FUTURE_WITH_STATEMENT) def emit(self, inst ): return self.graph.emit( inst ) @@ -525,6 +528,76 @@ def visitOr(self, node): self._visitTest(node, 'JUMP_IF_TRUE') + def visitCondExpr(self, node): + node.test.accept(self) + + end = self.newBlock() + falseblock = self.newBlock() + + self.emitop_block('JUMP_IF_FALSE', falseblock) + + self.emit('POP_TOP') + node.true_expr.accept(self) + self.emitop_block('JUMP_FORWARD', end) + + self.nextBlock(falseblock) + self.emit('POP_TOP') + node.false_expr.accept(self) + + self.nextBlock(end) + + __with_count = 0 + + def visitWith(self, node): + node.expr.accept(self) + self.emitop('LOAD_ATTR', '__context__') + self.emitop_int('CALL_FUNCTION', 0) + self.emit('DUP_TOP') + + ## exit = ctx.__exit__ + self.emitop('LOAD_ATTR', '__exit__') + exit = "$exit%d" % self.__with_count + var = "$var%d" % self.__with_count + self.__with_count = self.__with_count + 1 + self._implicitNameOp('STORE', exit) + + self.emitop('LOAD_ATTR', '__enter__') + self.emitop_int('CALL_FUNCTION', 0) + finally_block = self.newBlock() + body = self.newBlock() + + self.setups.append((TRY_FINALLY, body)) + + if node.var is not None: # VAR is present + self._implicitNameOp('STORE', var) + self.emitop_block('SETUP_FINALLY', finally_block) + self.nextBlock(body) + self._implicitNameOp('LOAD', var) + self._implicitNameOp('DELETE', var) + node.var.accept(self) + else: + self.emit('POP_TOP') + self.emitop_block('SETUP_FINALLY', finally_block) + self.nextBlock(body) + + node.body.accept(self) + + self.emit('POP_BLOCK') + self.setups.pop() + self.emitop_obj('LOAD_CONST', self.space.w_None) # WITH_CLEANUP checks for normal exit + self.nextBlock(finally_block) + self.setups.append((END_FINALLY, finally_block)) + + # find local variable with is context.__exit__ + self._implicitNameOp('LOAD', exit) + self._implicitNameOp('DELETE', exit) + + self.emit('WITH_CLEANUP') + self.emitop_int('CALL_FUNCTION', 3) + self.emit('POP_TOP') + self.emit('END_FINALLY') + self.setups.pop() + def visitCompare(self, node): node.expr.accept( self ) cleanup = self.newBlock() Modified: pypy/branch/njriley-trans/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/gateway.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/gateway.py Fri Mar 10 06:12:02 2006 @@ -140,7 +140,7 @@ def check__object(self, el, orig_sig, app_sig): if el not in (int, str, float): - assert False, "unsupported basic type in uwnrap_spec" + assert False, "unsupported basic type in unwrap_spec" name = el.__name__ argname = orig_sig.next_arg() assert not argname.startswith('w_'), ( Modified: pypy/branch/njriley-trans/pypy/interpreter/pycompiler.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pycompiler.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pycompiler.py Fri Mar 10 06:12:02 2006 @@ -78,7 +78,7 @@ # faked compiler import warnings -import __future__ +from pypy.tool import __future__ compiler_flags = 0 compiler_features = {} for fname in __future__.all_feature_names: Modified: pypy/branch/njriley-trans/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyopcode.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyopcode.py Fri Mar 10 06:12:02 2006 @@ -14,17 +14,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.rpython.objectmodel import we_are_translated from pypy.rpython.rarithmetic import intmask - -# load opcode.py as pythonopcode from our own lib -def load_opcode(): - import new, py - global pythonopcode - pythonopcode = new.module('opcode') - opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/2.4.1/opcode.py') - execfile(str(opcode_path), pythonopcode.__dict__) - -load_opcode() - +from pypy.tool import opcode as pythonopcode def unaryoperation(operationname): """NOT_RPYTHON""" @@ -647,6 +637,20 @@ block = pyframe.FinallyBlock(f, f.next_instr + offsettoend) f.blockstack.push(block) + def WITH_CLEANUP(f): + # see comment in END_FINALLY for stack state + w_unroller = f.valuestack.top(3) + unroller = f.space.interpclass_w(w_unroller) + if (isinstance(unroller, pyframe.SuspendedUnroller) + and isinstance(unroller.flowexc, pyframe.SApplicationException)): + f.valuestack.push(unroller.flowexc.operr.w_type) + f.valuestack.push(unroller.flowexc.operr.w_value) + f.valuestack.push(unroller.flowexc.operr.application_traceback) + else: + f.valuestack.push(f.space.w_None) + f.valuestack.push(f.space.w_None) + f.valuestack.push(f.space.w_None) + def call_function(f, oparg, w_star=None, w_starstar=None): n_arguments = oparg & 0xff n_keywords = (oparg>>8) & 0xff Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/astbuilder.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/astbuilder.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/astbuilder.py Fri Mar 10 06:12:02 2006 @@ -1,15 +1,18 @@ """This module provides the astbuilder class which is to be used by GrammarElements to directly build the AST during parsing -without going trhough the nested tuples step +without going through the nested tuples step """ from grammar import BaseGrammarBuilder, AbstractContext from pypy.interpreter.astcompiler import ast, consts -from pypy.interpreter.pyparser.pysymbol import _cpython_symbols as sym +from pypy.interpreter.pyparser import pythonparse import pypy.interpreter.pyparser.pytoken as tok from pypy.interpreter.pyparser.error import SyntaxError from pypy.interpreter.pyparser.parsestring import parsestr +sym = pythonparse.PYTHON_PARSER.symbols +sym_with = pythonparse.PYTHON_PARSER.with_grammar.symbols + DEBUG_MODE = 0 ### Parsing utilites ################################################# @@ -257,9 +260,9 @@ ifs = [] else: assert False, 'Unexpected token: expecting for in listcomp' - # + # # Original implementation: - # + # # if tokens[index].get_value() == 'for': # index += 1 # skip 'for' # ass_node = to_lvalue(tokens[index], consts.OP_ASSIGN) @@ -320,7 +323,7 @@ def get_docstring(builder,stmt): """parses a Stmt node. - + If a docstring if found, the Discard node is **removed** from and the docstring is returned. @@ -340,7 +343,7 @@ del stmt.nodes[0] doc = expr.value return doc - + def to_lvalue(ast_node, flags): lineno = ast_node.lineno @@ -388,7 +391,7 @@ lineno, 0, '') else: raise SyntaxError("can't assign to non-lvalue", - lineno, 0, '') + lineno, 0, '') def is_augassign( ast_node ): if ( isinstance( ast_node, ast.Name ) or @@ -410,7 +413,7 @@ i -= 1 atoms.reverse() return atoms - + #def eval_string(value): # """temporary implementation # @@ -466,7 +469,7 @@ def parse_attraccess(tokens): """parses token list like ['a', '.', 'b', '.', 'c', ...] - + and returns an ast node : ast.Getattr(Getattr(Name('a'), 'b'), 'c' ...) """ token = tokens[0] @@ -519,7 +522,7 @@ ## where Var and Expr are AST subtrees and Token is a not yet ## reduced token ## -## AST_RULES is kept as a dictionnary to be rpython compliant this is the +## ASTRULES is kept as a dictionnary to be rpython compliant this is the ## main reason why build_* functions are not methods of the AstBuilder class ## @@ -579,7 +582,7 @@ return lst[first:last] else: return [] - + def build_power(builder, nb): """power: atom trailer* ['**' factor]""" @@ -742,7 +745,10 @@ builder.push(TokenObject(tok.NAME, 'is not', lineno)) else: assert False, "TODO" # uh ? - + +def build_or_test(builder, nb): + return build_binary_expr(builder, nb, ast.Or) + def build_and_test(builder, nb): return build_binary_expr(builder, nb, ast.And) @@ -756,8 +762,18 @@ assert False, "not_test implementation incomplete in not_test" def build_test(builder, nb): - return build_binary_expr(builder, nb, ast.Or) - + atoms = get_atoms(builder, nb) + if len(atoms) == 1: + builder.push(atoms[0]) + elif len(atoms) == 5: + builder.push( + ast.CondExpr(atoms[2], atoms[0], atoms[4], atoms[1].lineno)) + else: + assert False, "invalid number of atoms for rule 'test'" + +# Note: we do not include a build_old_test() because it does not need to do +# anything. + def build_testlist(builder, nb): return build_binary_expr(builder, nb, ast.Tuple) @@ -837,7 +853,7 @@ stmts.extend(node.nodes) elif isinstance(node, TokenObject) and node.name == tok.ENDMARKER: # XXX Can't we just remove the last element of the list ? - break + break elif isinstance(node, TokenObject) and node.name == tok.NEWLINE: continue else: @@ -911,7 +927,6 @@ names, defaults, flags = parse_arglist(slicecut(atoms, 1, -2)) builder.push(ast.Lambda(names, defaults, flags, code, lineno)) - def build_trailer(builder, nb): """trailer: '(' ')' | '(' arglist ')' | '[' subscriptlist ']' | '.' NAME """ @@ -1009,7 +1024,7 @@ else: builder.push(SlicelistObject('slice', sliceinfos, lineno)) - + def build_listmaker(builder, nb): """listmaker: test ( list_for | (',' test)* [','] )""" atoms = get_atoms(builder, nb) @@ -1223,6 +1238,25 @@ else_ = atoms[6] builder.push(ast.While(test, body, else_, atoms[0].lineno)) +def build_with_stmt(builder, nb): + """with_stmt: 'with' test [ NAME expr ] ':' suite""" + + atoms = get_atoms(builder, nb) + # skip 'with' + test = atoms[1] + if len(atoms) == 4: + body = atoms[3] + var = None + # if there is an "as" clause + else: + token = atoms[2] + assert isinstance(token, TokenObject) + if token.get_value() != 'as': + raise SyntaxError("invalid syntax", token.lineno, token.col) + varexpr = atoms[3] + var = to_lvalue(varexpr, consts.OP_ASSIGN) + body = atoms[5] + builder.push(ast.With(test, body, var, atoms[0].lineno)) def build_import_name(builder, nb): """import_name: 'import' dotted_as_names @@ -1311,6 +1345,12 @@ names.append((name, as_name)) if index < l: # case ',' index += 1 + if from_name == '__future__': + for name, asname in names: + if name == 'with_statement': + # found from __future__ import with_statement + if not builder.with_enabled: + raise pythonparse.AlternateGrammarException() builder.push(ast.From(from_name, names, atoms[0].lineno)) @@ -1325,7 +1365,7 @@ def build_del_stmt(builder, nb): atoms = get_atoms(builder, nb) builder.push(to_lvalue(atoms[1], consts.OP_DELETE)) - + def build_assert_stmt(builder, nb): """assert_stmt: 'assert' test [',' test]""" @@ -1404,7 +1444,7 @@ ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite) # NB compile.c makes sure that the default except clause is last except_clause: 'except' [test [',' test]] - + """ atoms = get_atoms(builder, nb) l = len(atoms) @@ -1433,59 +1473,69 @@ else_ = atoms[index+2] # skip ':' builder.push(ast.TryExcept(body, handlers, else_, atoms[0].lineno)) - -ASTRULES = { - sym['atom'] : build_atom, - sym['power'] : build_power, - sym['factor'] : build_factor, - sym['term'] : build_term, - sym['arith_expr'] : build_arith_expr, - sym['shift_expr'] : build_shift_expr, - sym['and_expr'] : build_and_expr, - sym['xor_expr'] : build_xor_expr, - sym['expr'] : build_expr, - sym['comparison'] : build_comparison, - sym['comp_op'] : build_comp_op, - sym['and_test'] : build_and_test, - sym['not_test'] : build_not_test, - sym['test'] : build_test, - sym['testlist'] : build_testlist, - sym['expr_stmt'] : build_expr_stmt, - sym['small_stmt'] : return_one, - sym['simple_stmt'] : build_simple_stmt, - sym['single_input'] : build_single_input, - sym['file_input'] : build_file_input, - sym['testlist_gexp'] : build_testlist_gexp, - sym['lambdef'] : build_lambdef, - sym['trailer'] : build_trailer, - sym['arglist'] : build_arglist, - sym['subscript'] : build_subscript, - sym['listmaker'] : build_listmaker, - sym['funcdef'] : build_funcdef, - sym['classdef'] : build_classdef, - sym['return_stmt'] : build_return_stmt, - sym['suite'] : build_suite, - sym['if_stmt'] : build_if_stmt, - sym['pass_stmt'] : build_pass_stmt, - sym['break_stmt'] : build_break_stmt, - sym['for_stmt'] : build_for_stmt, - sym['while_stmt'] : build_while_stmt, - sym['import_name'] : build_import_name, - sym['import_from'] : build_import_from, - sym['yield_stmt'] : build_yield_stmt, - sym['continue_stmt'] : build_continue_stmt, - sym['del_stmt'] : build_del_stmt, - sym['assert_stmt'] : build_assert_stmt, - sym['exec_stmt'] : build_exec_stmt, - sym['print_stmt'] : build_print_stmt, - sym['global_stmt'] : build_global_stmt, - sym['raise_stmt'] : build_raise_stmt, - sym['try_stmt'] : build_try_stmt, - sym['exprlist'] : build_exprlist, - sym['decorator'] : build_decorator, - sym['eval_input'] : build_eval_input, +ASTRULES_Template = { + 'atom' : build_atom, + 'power' : build_power, + 'factor' : build_factor, + 'term' : build_term, + 'arith_expr' : build_arith_expr, + 'shift_expr' : build_shift_expr, + 'and_expr' : build_and_expr, + 'xor_expr' : build_xor_expr, + 'expr' : build_expr, + 'comparison' : build_comparison, + 'comp_op' : build_comp_op, + 'or_test' : build_or_test, + 'and_test' : build_and_test, + 'not_test' : build_not_test, + 'test' : build_test, + 'testlist' : build_testlist, + 'expr_stmt' : build_expr_stmt, + 'small_stmt' : return_one, + 'simple_stmt' : build_simple_stmt, + 'single_input' : build_single_input, + 'file_input' : build_file_input, + 'testlist_gexp' : build_testlist_gexp, + 'lambdef' : build_lambdef, + 'old_lambdef' : build_lambdef, + 'trailer' : build_trailer, + 'arglist' : build_arglist, + 'subscript' : build_subscript, + 'listmaker' : build_listmaker, + 'funcdef' : build_funcdef, + 'classdef' : build_classdef, + 'return_stmt' : build_return_stmt, + 'suite' : build_suite, + 'if_stmt' : build_if_stmt, + 'pass_stmt' : build_pass_stmt, + 'break_stmt' : build_break_stmt, + 'for_stmt' : build_for_stmt, + 'while_stmt' : build_while_stmt, + 'import_name' : build_import_name, + 'import_from' : build_import_from, + 'yield_stmt' : build_yield_stmt, + 'continue_stmt' : build_continue_stmt, + 'del_stmt' : build_del_stmt, + 'assert_stmt' : build_assert_stmt, + 'exec_stmt' : build_exec_stmt, + 'print_stmt' : build_print_stmt, + 'global_stmt' : build_global_stmt, + 'raise_stmt' : build_raise_stmt, + 'try_stmt' : build_try_stmt, + 'exprlist' : build_exprlist, + 'decorator' : build_decorator, + 'eval_input' : build_eval_input, } +# Build two almost identical ASTRULES dictionaries +ASTRULES = dict([(sym[key], value) for (key, value) in + ASTRULES_Template.iteritems()]) + +ASTRULES_Template['with_stmt'] = build_with_stmt +ASTRULES_with = dict([(sym_with[key], value) for (key, value) in + (ASTRULES_Template).iteritems()]) +del ASTRULES_Template + ## Stack elements definitions ################################### class BaseRuleObject(ast.Node): @@ -1494,8 +1544,8 @@ self.count = count self.lineno = lineno # src.getline() self.col = 0 # src.getcol() - - + + class RuleObject(BaseRuleObject): """A simple object used to wrap a rule or token""" def __init__(self, name, count, lineno): @@ -1511,18 +1561,18 @@ class TempRuleObject(BaseRuleObject): """used to keep track of how many items get_atom() should pop""" - + def __init__(self, name, count, lineno): BaseRuleObject.__init__(self, count, lineno) self.temp_rulename = name - + def __str__(self): return "" % (self.temp_rulename, self.count) def __repr__(self): return "" % (self.temp_rulename, self.count) - + class TokenObject(ast.Node): """A simple object used to wrap a rule or token""" def __init__(self, name, value, lineno): @@ -1532,7 +1582,7 @@ # self.line = 0 # src.getline() self.col = 0 # src.getcol() self.lineno = lineno - + def get_name(self): return tok.tok_rpunct.get(self.name, tok.tok_name.get(self.name, str(self.name))) @@ -1542,10 +1592,10 @@ if value is None: value = '' return value - + def __str__(self): return "" % (self.get_name(), self.value) - + def __repr__(self): return "" % (self.get_name(), self.value) @@ -1568,13 +1618,13 @@ def __str__(self): return "" % self.value - + def __repr__(self): return "" % self.value - + class SubscriptObject(ObjectAccessor): """helper class to build subscript list - + self.value represents the __getitem__ argument """ def __init__(self, name, value, lineno): @@ -1584,7 +1634,7 @@ def __str__(self): return "" % self.value - + def __repr__(self): return "" % self.value @@ -1603,10 +1653,10 @@ def __str__(self): return "" % self.value - + def __repr__(self): return "" % self.value - + class AstBuilderContext(AbstractContext): """specific context management for AstBuidler""" @@ -1622,7 +1672,13 @@ self.rule_stack = [] self.space = space self.source_encoding = None - + self.ASTRULES = ASTRULES + self.with_enabled = False + + def enable_with(self): + self.ASTRULES = ASTRULES_with + self.with_enabled = True + def context(self): return AstBuilderContext(self.rule_stack) @@ -1661,7 +1717,7 @@ if rule.is_root(): ## if DEBUG_MODE: ## print "ALT:", sym.sym_name[rule.codename], self.rule_stack - builder_func = ASTRULES.get(rule.codename, None) + builder_func = self.ASTRULES.get(rule.codename, None) if builder_func: builder_func(self, 1) else: @@ -1682,7 +1738,7 @@ if rule.is_root(): ## if DEBUG_MODE: ## print "SEQ:", sym.sym_name[rule.codename] - builder_func = ASTRULES.get(rule.codename, None) + builder_func = self.ASTRULES.get(rule.codename, None) if builder_func: # print "REDUCING SEQUENCE %s" % sym.sym_name[rule.codename] builder_func(self, elts_number) @@ -1718,12 +1774,12 @@ l = space.builtin.get('long') return space.call_function(l, space.wrap(value), space.wrap(base)) if value.endswith('j') or value.endswith('J'): - c = space.builtin.get('complex') + c = space.builtin.get('complex') return space.call_function(c, space.wrap(value)) try: i = space.builtin.get('int') return space.call_function(i, space.wrap(value), space.wrap(base)) - except: + except: f = space.builtin.get('float') return space.call_function(f, space.wrap(value)) @@ -1760,4 +1816,4 @@ else: obj2 = "-" print "% 3d | %30s | %30s" % (i, obj1, obj2) - + Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/ebnfparse.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/ebnfparse.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/ebnfparse.py Fri Mar 10 06:12:02 2006 @@ -260,7 +260,7 @@ from pprint import pprint if __name__ == "__main__": - grambuild = parse_grammar(file('data/Grammar2.3')) + grambuild = parse_grammar(file('data/Grammar2.5a')) for i,r in enumerate(grambuild.items): print "% 3d : %s" % (i, r) pprint(grambuild.terminals.keys()) Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/pysymbol.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/pysymbol.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/pysymbol.py Fri Mar 10 06:12:02 2006 @@ -1,9 +1,4 @@ -# replacement for the CPython symbol module -try: - from pypy.interpreter.pyparser import symbol -except ImportError: - # for standalone testing - import symbol +from pypy.interpreter.pyparser import symbol # try to avoid numeric values conflict with tokens # it's important for CPython, but I'm not so sure it's still @@ -54,19 +49,45 @@ _cpython_symbols = SymbolMapper( symbol.sym_name ) - -# prepopulate symbol table from symbols used by CPython -for _value, _name in _cpython_symbols.sym_name.items(): - globals()[_name] = _value - - - -def update_symbols( parser ): - """Update the symbol module according to rules - in PythonParser instance : parser""" - for rule in parser.rules: - _cpython_symbols.add_symbol( rule ) - # There is no symbol in this module until the grammar is loaded # once loaded the grammar parser will fill the mappings with the # grammar symbols + +def gen_symbol_file(fname): + """ + Generate a compatible symbol file for symbol.py, using the grammar that has + been generated from the grammar in the PyPy parser. (Note that we assume + that the parser generates the tokens deterministically.) + """ + + import ebnfparse + gram = ebnfparse.parse_grammar( file(fname) ) + + import os.path + f = open(os.path.join(os.path.dirname(__file__), 'symbol.py'), 'w') + print >> f, """ +# This file is automatically generated; please don't muck it up! +# +# To update the symbols in this file, call this function from python_grammar() +# and call PyPy. +""" + for k, v in gram.symbols.sym_name.iteritems(): + if k >= 0: + print >> f, '%s = %s' % (v, k) + + print >> f, """ + +# Generate sym_name +sym_name = {} +for _name, _value in globals().items(): + if type(_value) is type(0): + sym_name[_value] = _name +""" + f.close() + +if __name__ == '__main__': + import sys + if len(sys.argv) != 2: + print 'Call pysymbol with the filename of the python grammar' + sys.exit(0) + gen_symbol_file(sys.argv[1]) Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonparse.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonparse.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonparse.py Fri Mar 10 06:12:02 2006 @@ -10,6 +10,7 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool.option import Options from pythonlexer import Source, match_encoding_declaration +from pypy.interpreter.astcompiler.consts import CO_FUTURE_WITH_STATEMENT import pysymbol import ebnfparse import sys @@ -18,6 +19,9 @@ from codeop import PyCF_DONT_IMPLY_DEDENT +class AlternateGrammarException(Exception): + pass + class PythonParser(object): """Wrapper class for python grammar""" def __init__(self, grammar_builder): @@ -25,6 +29,8 @@ self.rules = grammar_builder.rules # Build first sets for each rule (including anonymous ones) grammar.build_first_sets(self.items) + self.symbols = grammar_builder.symbols + self.with_grammar = None def parse_source(self, textsrc, goal, builder, flags=0): """Parse a python source according to goal""" @@ -44,19 +50,30 @@ flags &= ~PyCF_DONT_IMPLY_DEDENT return self.parse_lines(lines, goal, builder, flags) + def parse_lines(self, lines, goal, builder, flags=0): - goalnumber = pysymbol._cpython_symbols.sym_values[goal] + if (self.with_grammar is not None and # don't recurse into ourself + flags & CO_FUTURE_WITH_STATEMENT): + builder.enable_with() + return self.with_grammar.parse_lines(lines, goal, builder, flags) + goalnumber = self.symbols.sym_values[goal] target = self.rules[goalnumber] src = Source(lines, flags) - - result = target.match(src, builder) + + result = None + try: + result = target.match(src, builder) + except AlternateGrammarException: # handle from __future__ import with_statement + if self.with_grammar is not None: + builder.enable_with() + return self.with_grammar.parse_lines(lines, goal, builder, flags) if not result: line, lineno = src.debug() # XXX needs better error messages raise SyntaxError("invalid syntax", lineno, -1, line) # return None return builder - + _recode_to_utf8 = gateway.applevel(r''' def _recode_to_utf8(text, encoding): return unicode(text, encoding).encode("utf-8") @@ -96,7 +113,7 @@ if eol2 < 0: return _check_line_for_encoding(s[eol + 1:]) return _check_line_for_encoding(s[eol + 1:eol2]) - + def _check_line_for_encoding(line): """returns the declared encoding or None""" i = 0 @@ -112,7 +129,9 @@ """returns the python grammar corresponding to our CPython version""" if version == "native": _ver = PYTHON_VERSION - elif version in ("2.3","2.4"): + elif version == "stable": + _ver = "_stablecompiler" + elif version in ("2.3","2.4","2.5a"): _ver = version return os.path.join( os.path.dirname(__file__), "data", "Grammar" + _ver ), _ver @@ -130,6 +149,7 @@ debug_print( "Loading grammar %s" % PYTHON_GRAMMAR ) PYTHON_PARSER = python_grammar( PYTHON_GRAMMAR ) +PYTHON_PARSER.with_grammar = python_grammar( PYTHON_GRAMMAR + '_with' ) def reload_grammar(version): """helper function to test with pypy different grammars""" @@ -141,7 +161,7 @@ def parse_file_input(pyf, gram, builder ): """Parse a python file""" return gram.parse_source( pyf.read(), "file_input", builder ) - + def parse_single_input(textsrc, gram, builder ): """Parse a python single statement""" return gram.parse_source( textsrc, "single_input", builder ) @@ -152,9 +172,12 @@ def grammar_rules( space ): - return space.wrap( PYTHON_PARSER.rules ) + w_rules = space.newdict([]) + for key, value in PYTHON_PARSER.rules.iteritems(): + space.setitem(w_rules, space.wrap(key), space.wrap(value)) + return w_rules def make_rule( space, w_rule ): rule = space.str_w( w_rule ) - + Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonutil.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonutil.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/pythonutil.py Fri Mar 10 06:12:02 2006 @@ -5,7 +5,6 @@ import pythonparse from tuplebuilder import TupleBuilder from astbuilder import AstBuilder -from pypy.interpreter.pyparser import pysymbol PYTHON_PARSER = pythonparse.PYTHON_PARSER TARGET_DICT = { @@ -50,7 +49,8 @@ pyf.close() return pypy_parse(source, 'exec', lineno) -def internal_pypy_parse(source, mode='exec', lineno=False, flags=0, space=None): +def internal_pypy_parse(source, mode='exec', lineno=False, flags=0, space=None, + parser = PYTHON_PARSER): """This function has no other role than testing the parser's annotation annotateme() is basically the same code that pypy_parse(), but with the @@ -60,11 +60,11 @@ tuples (StackElement is only a wrapper class around these tuples) """ - builder = TupleBuilder(PYTHON_PARSER.rules, lineno=False) + builder = TupleBuilder(parser.rules, lineno=False) if space is not None: builder.space = space target_rule = TARGET_DICT[mode] - PYTHON_PARSER.parse_source(source, target_rule, builder, flags) + parser.parse_source(source, target_rule, builder, flags) stack_element = builder.stack[-1] return (builder.source_encoding, stack_element) @@ -72,12 +72,9 @@ """NOT_RPYTHON""" source_encoding, stack_element = parse_result nested_tuples = stack_element.as_tuple(lineno) - if source_encoding is not None: - return (pysymbol.encoding_decl, nested_tuples, source_encoding) - else: - return nested_tuples + return nested_tuples -def pypy_parse(source, mode='exec', lineno=False, flags=0): +def pypy_parse(source, mode='exec', lineno=False, flags=0, parser = PYTHON_PARSER): """ NOT_RPYTHON ! parse using PyPy's parser module and return @@ -90,13 +87,14 @@ - The encoding string or None if there were no encoding statement nested tuples """ - source_encoding, stack_element = internal_pypy_parse(source, mode, lineno=lineno, flags=lineno) + source_encoding, stack_element = internal_pypy_parse(source, mode, lineno=lineno, + flags=lineno, parser = parser) # convert the stack element into nested tuples (caution, the annotator # can't follow this call) return parse_result_to_nested_tuples((source_encoding, stack_element), lineno=lineno) ## convenience functions for computing AST objects using recparser -def ast_from_input(input, mode, transformer): +def ast_from_input(input, mode, transformer, parser = PYTHON_PARSER): """converts a source input into an AST - input : the source to be converted @@ -107,7 +105,7 @@ here to explicitly import compiler or stablecompiler or etc. This is to be fixed in a clean way """ - tuples = pypy_parse(input, mode, True) + tuples = pypy_parse(input, mode, True, parser) ast = transformer.compile_node(tuples) return ast Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/symbol.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/symbol.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/symbol.py Fri Mar 10 06:12:02 2006 @@ -1,15 +1,9 @@ -#! /usr/bin/env python - -"""Non-terminal symbols of Python grammar (from "graminit.h").""" # This file is automatically generated; please don't muck it up! # -# To update the symbols in this file, 'cd' to the top directory of -# the python source tree after building the interpreter and run: -# -# python Lib/symbol.py +# To update the symbols in this file, call this function from python_grammar() +# and call PyPy. -#--start constants-- single_input = 256 file_input = 257 eval_input = 258 @@ -88,20 +82,14 @@ gen_if = 331 testlist1 = 332 encoding_decl = 333 -#--end constants-- +old_test = 334 +or_test = 335 +old_lambdef = 336 + +# Generate sym_name sym_name = {} for _name, _value in globals().items(): if type(_value) is type(0): sym_name[_value] = _name - -def main(): - import sys - import token - if len(sys.argv) == 1: - sys.argv = sys.argv + ["Include/graminit.h", "Lib/symbol.py"] - token.main() - -if __name__ == "__main__": - main() Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astbuilder.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astbuilder.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astbuilder.py Fri Mar 10 06:12:02 2006 @@ -1,6 +1,6 @@ import os -from pypy.interpreter.pyparser.pythonparse import PYTHON_PARSER +from pypy.interpreter.pyparser import pythonparse from pypy.interpreter.pyparser.astbuilder import AstBuilder from pypy.interpreter.pyparser.pythonutil import ast_from_input from pypy.interpreter.stablecompiler.transformer import Transformer @@ -206,8 +206,22 @@ "[a, (b,c), d] = e", "a, (b, c), d = e", ] -EXPECTED["k[v,]"] = "Module(None, Stmt([Discard(Subscript(Name('k'), 2, Tuple([Name('v')])))]))" -EXPECTED["m[a,b]"] = "Module(None, Stmt([Discard(Subscript(Name('m'), 2, Tuple([Name('a'), Name('b')])))]))" + +# We do not export the following tests because we would have to implement 2.5 +# features in the stable compiler (other than just building the AST). +expressions_inbetweenversions = expressions + [ + "1 if True else 2", + "1 if False else 2", + ] + +EXPECTED["k[v,]"] = ("Module(None, Stmt([Discard(Subscript(Name('k'), 2, " + "Tuple([Name('v')])))]))") +EXPECTED["m[a,b]"] = ("Module(None, Stmt([Discard(Subscript(Name('m'), 2, " + "Tuple([Name('a'), Name('b')])))]))") +EXPECTED["1 if True else 2"] = ("Module(None, Stmt([Discard(CondExpr(" + "Name('True'), Const(1), Const(2)))]))") +EXPECTED["1 if False else 2"] = ("Module(None, Stmt([Discard(CondExpr(" + "Name('False'), Const(1), Const(2)))]))") funccalls = [ "l = func()", @@ -601,7 +615,7 @@ TESTS = [ constants, - expressions, + expressions_inbetweenversions, augassigns, comparisons, funccalls, @@ -690,12 +704,16 @@ def ast_parse_expr(expr, target='single'): target = TARGET_DICT[target] builder = AstBuilder(space=FakeSpace()) - PYTHON_PARSER.parse_source(expr, target, builder) + pythonparse.PYTHON_PARSER.parse_source(expr, target, builder) return builder +# Create parser from Grammar_stable, not current grammar. +stable_grammar, _ = pythonparse.get_grammar_file("stable") +stable_parser = pythonparse.python_grammar(stable_grammar) + def tuple_parse_expr(expr, target='single'): t = Transformer("dummyfile") - return ast_from_input(expr, target, t) + return ast_from_input(expr, target, t, stable_parser) def check_expression(expr, target='single'): r1 = ast_parse_expr(expr, target) @@ -727,6 +745,11 @@ for expr in family: yield check_expression, expr, 'exec' +NEW_GRAMMAR_SNIPPETS = [ + 'snippet_with_1.py', + 'snippet_with_2.py', + ] + SNIPPETS = [ 'snippet_1.py', 'snippet_several_statements.py', @@ -769,9 +792,14 @@ ] def test_snippets(): - for snippet_name in SNIPPETS: + for snippet_name in SNIPPETS + NEW_GRAMMAR_SNIPPETS: filepath = os.path.join(os.path.dirname(__file__), 'samples', snippet_name) source = file(filepath).read() + # To avoid using the stable compiler we pull an explicit AST out of the snippet + if source.startswith('# EXPECT:'): + firstline,_ = source.split('\n', 1) + firstline = firstline[len('# EXPECT:'):].strip() + EXPECTED[source] = firstline yield check_expression, source, 'exec' def test_libstuff(): Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astcompiler.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astcompiler.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_astcompiler.py Fri Mar 10 06:12:02 2006 @@ -1,5 +1,5 @@ import os -from pypy.interpreter.pyparser.pythonparse import PYTHON_PARSER +from pypy.interpreter.pyparser import pythonparse from pypy.interpreter.pyparser.astbuilder import AstBuilder from pypy.interpreter.pyparser.tuplebuilder import TupleBuilder from pypy.interpreter.pycode import PyCode @@ -63,7 +63,7 @@ def ast_parse_expr(expr, target='single', space=FakeSpace()): target = TARGET_DICT[target] builder = AstBuilder(space=space) - PYTHON_PARSER.parse_source(expr, target, builder) + pythonparse.PYTHON_PARSER.parse_source(expr, target, builder) return builder.rule_stack[-1] @@ -80,10 +80,15 @@ rcode = codegen.getCode() return rcode + +# Create parser from Grammar_stable, not current grammar. +stable_grammar, _ = pythonparse.get_grammar_file("stable") +stable_parser = pythonparse.python_grammar(stable_grammar) + def compile_with_testcompiler(expr, target='exec', space=FakeSpace()): target2 = TARGET_DICT['exec'] # xxx exec: single not really tested builder = TupleBuilder() - PYTHON_PARSER.parse_source(expr, target2, builder) + stable_parser.parse_source(expr, target2, builder) tuples = builder.stack[-1].as_tuple(True) from pypy.interpreter.stablecompiler import transformer, pycodegen, misc ast = transformer.Transformer('').compile_node(tuples) Modified: pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_samples.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_samples.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/pyparser/test/test_samples.py Fri Mar 10 06:12:02 2006 @@ -21,6 +21,10 @@ #"snippet_import_statements.py", "snippet_decorators.py", ] +SKIP_ALWAYS = [ + "snippet_with_1.py", + "snippet_with_2.py", +] REAL_EXPECTED_OUTPUT = { # for snippets that show bugs of Python's compiler package "snippet_transformer_bug.py": @@ -73,6 +77,8 @@ for fname in os.listdir(samples_dir): if not fname.endswith('.py'): continue + if fname in SKIP_ALWAYS: + continue if GRAMMAR_MISMATCH and fname in SKIP_IF_NOT_NATIVE: print "Skipping", fname continue Modified: pypy/branch/njriley-trans/pypy/interpreter/stablecompiler/transformer.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/stablecompiler/transformer.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/stablecompiler/transformer.py Fri Mar 10 06:12:02 2006 @@ -26,14 +26,26 @@ # and replace OWNER, ORGANIZATION, and YEAR as appropriate. # make sure we import the parser with the correct grammar -import pypy.interpreter.pyparser.pythonparse +from pypy.interpreter.pyparser import pythonparse + +import pypy.interpreter.pyparser.pythonparse as pythonparse + from pypy.interpreter.stablecompiler.ast import * import parser -import pypy.interpreter.pyparser.pysymbol as symbol import pypy.interpreter.pyparser.pytoken as token import sys -sym_name = symbol._cpython_symbols.sym_name +# Create parser from Grammar_stable, not current grammar. +stable_grammar, _ = pythonparse.get_grammar_file("stable") +stable_parser = pythonparse.python_grammar(stable_grammar) + +sym_name = stable_parser.symbols.sym_name + +class symbol: + pass + +for value, name in sym_name.iteritems(): + setattr(symbol, name, value) # transforming is requiring a lot of recursion depth so make sure we have enough if sys.getrecursionlimit()<5000: @@ -308,9 +320,12 @@ return Lambda(names, defaults, flags, code, lineno=nodelist[1][2]) + # (This is like lambdef but it uses the old_test instead.) + # old_lambdef: 'lambda' [varargslist] ':' old_test + old_lambdef = lambdef + def classdef(self, nodelist): # classdef: 'class' NAME ['(' testlist ')'] ':' suite - name = nodelist[1][1] doc = self.get_docstring(nodelist[-1]) if nodelist[2][0] == token.COLON: @@ -579,7 +594,7 @@ def testlist(self, nodelist): # testlist: expr (',' expr)* [','] - # testlist_safe: test [(',' test)+ [',']] + # testlist_safe: old_test [(',' old_test)+ [',']] # exprlist: expr (',' expr)* [','] return self.com_binary(Tuple, nodelist) @@ -594,15 +609,33 @@ return self.testlist(nodelist) def test(self, nodelist): - # and_test ('or' and_test)* | lambdef - if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: - return self.lambdef(nodelist[0]) - return self.com_binary(Or, nodelist) + # test: or_test ['if' or_test 'else' test] | lambdef + if len(nodelist) == 1: + if nodelist[0][0] == symbol.lambdef: + return self.lambdef(nodelist[0]) + else: + # Normal or-expression + return self.com_node(nodelist[0]) + else: + # Here we implement conditional expressions + return ast.CondExpr(nodelist[2], nodelist[0], nodelist[4], + nodelist[1].lineno) def and_test(self, nodelist): # not_test ('and' not_test)* return self.com_binary(And, nodelist) + def old_test(self, nodelist): + # old_test: or_test | old_lambdef + if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: + return self.lambdef(nodelist[0]) + assert len(nodelist) == 1 + return self.com_node(nodelist[0]) + + def or_test(self, nodelist): + # or_test: and_test ('or' and_test)* + return self.com_binary(Or, nodelist) + def not_test(self, nodelist): # 'not' not_test | comparison result = self.com_node(nodelist[-1]) @@ -1396,6 +1429,8 @@ symbol.testlist, symbol.testlist_safe, symbol.test, + symbol.old_test, + symbol.or_test, symbol.and_test, symbol.not_test, symbol.comparison, @@ -1421,54 +1456,10 @@ token.NOTEQUAL : '!=', } -_legal_node_types = [ - symbol.funcdef, - symbol.classdef, - symbol.stmt, - symbol.small_stmt, - symbol.flow_stmt, - symbol.simple_stmt, - symbol.compound_stmt, - symbol.expr_stmt, - symbol.print_stmt, - symbol.del_stmt, - symbol.pass_stmt, - symbol.break_stmt, - symbol.continue_stmt, - symbol.return_stmt, - symbol.raise_stmt, - symbol.import_stmt, - symbol.global_stmt, - symbol.exec_stmt, - symbol.assert_stmt, - symbol.if_stmt, - symbol.while_stmt, - symbol.for_stmt, - symbol.try_stmt, - symbol.suite, - symbol.testlist, - symbol.testlist_safe, - symbol.test, - symbol.and_test, - symbol.not_test, - symbol.comparison, - symbol.exprlist, - symbol.expr, - symbol.xor_expr, - symbol.and_expr, - symbol.shift_expr, - symbol.arith_expr, - symbol.term, - symbol.factor, - symbol.power, - symbol.atom, - ] - -if hasattr(symbol, 'yield_stmt'): - _legal_node_types.append(symbol.yield_stmt) - _assign_types = [ symbol.test, + symbol.old_test, + symbol.or_test, symbol.and_test, symbol.not_test, symbol.comparison, Modified: pypy/branch/njriley-trans/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/branch/njriley-trans/pypy/interpreter/test/test_syntax.py (original) +++ pypy/branch/njriley-trans/pypy/interpreter/test/test_syntax.py Fri Mar 10 06:12:02 2006 @@ -248,6 +248,271 @@ raise +class AppTestCondExpr: + + def test_condexpr(self): + for s, expected in [("x = 1 if True else 2", 1), + ("x = 1 if False else 2", 2)]: + exec s + assert x == expected + +class AppTestWith: + def test_with_1(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + pass + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + pass + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontext = ContextFactory() + with acontext: + pass + """ + exec s + + assert acontext.calls == '__context__ __enter__ __exit__'.split() + + def test_with_2(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + with acontextfact as avar: + avar.append('__body__') + pass + """ + exec s + + assert acontextfact.exit_params == (None, None, None) + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + + def test_with_3(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + try: + with acontextfact as avar: + avar.append('__body__') + raise error + avar.append('__after_raise__') + except RuntimeError: + pass + else: + raise AssertionError('With did not raise RuntimeError') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + assert acontextfact.exit_params[0:2] == (RuntimeError, error) + import types + assert isinstance(acontextfact.exit_params[2], types.TracebackType) + + def test_with_4(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + for x in 1,: + with acontextfact as avar: + avar.append('__body__') + break + avar.append('__after_break__') + else: + raise AssertionError('Break failed with With, reached else clause') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + assert acontextfact.exit_params == (None, None, None) + + def test_with_5(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + for x in 1,: + with acontextfact as avar: + avar.append('__body__') + continue + avar.append('__after_break__') + else: + avar.append('__continue__') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __continue__'.split() + assert acontextfact.exit_params == (None, None, None) + + def test_with_6(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + def g(acontextfact): + with acontextfact as avar: + avar.append('__body__') + return '__return__' + avar.append('__after_return__') + acontextfact.calls.append(g(acontextfact)) + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __return__'.split() + assert acontextfact.exit_params == (None, None, None) + + def test_with_7(self): + exec "with = 9" + + def test_with_8(self): + try: + exec "from __future__ import with_statement\nwith = 9" + except SyntaxError: + pass + else: + assert False, 'Assignment to with did not raise SyntaxError' + + def test_with_9(self): + s = """from __future__ import with_statement +if 1: + compile('''with x: + pass''', '', 'exec') + """ + exec s + if __name__ == '__main__': # only to check on top of CPython (you need 2.4) from py.test import raises Modified: pypy/branch/njriley-trans/pypy/jit/hintrtyper.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/hintrtyper.py (original) +++ pypy/branch/njriley-trans/pypy/jit/hintrtyper.py Fri Mar 10 06:12:02 2006 @@ -12,6 +12,8 @@ class HintTypeSystem(TypeSystem): name = "hinttypesystem" + offers_exceptiondata = False + def perform_normalizations(self, rtyper): pass # for now @@ -27,7 +29,7 @@ return hs.concretetype class HintRTyper(RPythonTyper): - + def __init__(self, hannotator, timeshifter): RPythonTyper.__init__(self, hannotator, type_system=HintTypeSystem.instance) Modified: pypy/branch/njriley-trans/pypy/jit/hinttimeshift.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/hinttimeshift.py (original) +++ pypy/branch/njriley-trans/pypy/jit/hinttimeshift.py Fri Mar 10 06:12:02 2006 @@ -43,13 +43,17 @@ self.ll_build_jitstate_graph = self.annhelper.getgraph( rtimeshift.ll_build_jitstate, [], self.s_JITState) - self.ll_signed_box_graph = self.annhelper.getgraph( - rtimeshift.ll_signed_box, - [self.s_JITState, annmodel.SomeInteger()], + self.ll_int_box_graph = self.annhelper.getgraph( + rtimeshift.ll_int_box, + [rgenop.s_ConstOrVar], self.s_RedBox) - self.ll_adr_box_graph = self.annhelper.getgraph( - rtimeshift.ll_adr_box, - [self.s_JITState, annmodel.SomeAddress(), annmodel.SomePtr(rgenop.CONSTORVAR)], + self.ll_addr_box_graph = self.annhelper.getgraph( + rtimeshift.ll_addr_box, + [rgenop.s_ConstOrVar], + self.s_RedBox) + self.ll_double_box_graph = self.annhelper.getgraph( + rtimeshift.ll_int_box, + [rgenop.s_ConstOrVar], self.s_RedBox) self.ll_var_box_graph = self.annhelper.getgraph( rtimeshift.ll_var_box, Modified: pypy/branch/njriley-trans/pypy/jit/rtimeshift.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/rtimeshift.py (original) +++ pypy/branch/njriley-trans/pypy/jit/rtimeshift.py Fri Mar 10 06:12:02 2006 @@ -45,31 +45,28 @@ class ConstRedBox(RedBox): "A red box that contains a run-time constant." + def __init__(self, genvar): + self.genvar = genvar + + def getgenvar(self): + return self.genvar + def ll_fromvalue(value): T = lltype.typeOf(value) + gv = rgenop.genconst(value) if isinstance(T, lltype.Ptr): - return AddrRedBox(llmemory.cast_ptr_to_adr(value), rgenop.genconst(value)) + return AddrRedBox(gv) elif T is lltype.Float: - return DoubleRedBox(value) + return DoubleRedBox(gv) else: assert T is not lltype.Void, "cannot make red boxes of voids" # XXX what about long longs? - return IntRedBox(lltype.cast_primitive(lltype.Signed, value)) + return IntRedBox(gv) ll_fromvalue = staticmethod(ll_fromvalue) def ll_getvalue(self, T): # note: this is specialized by low-level type T, as a low-level helper - if isinstance(T, lltype.Ptr): - assert isinstance(self, AddrRedBox) - return llmemory.cast_adr_to_ptr(self.adrvalue, T) - elif T is lltype.Float: - assert isinstance(self, DoubleRedBox) - return self.dblvalue - else: - assert T is not lltype.Void, "no red box contains voids" - assert isinstance(self, IntRedBox) - # XXX what about long longs? - return lltype.cast_primitive(T, self.intvalue) + return rgenop.revealconst(T, self.genvar) def ll_getvalue(box, T): return box.ll_getvalue(T) @@ -78,44 +75,25 @@ class IntRedBox(ConstRedBox): "A red box that contains a constant integer-like value." - def __init__(self, intvalue): - self.intvalue = intvalue - - def getgenvar(self): - return rgenop.genconst(self.intvalue) - def same_constant(self, other): - return isinstance(other, IntRedBox) and self.intvalue == other.intvalue + return (isinstance(other, IntRedBox) and + self.ll_getvalue(lltype.Signed) == other.ll_getvalue(lltype.Signed)) class DoubleRedBox(ConstRedBox): "A red box that contains a constant double-precision floating point value." - def __init__(self, dblvalue): - self.dblvalue = dblvalue - - def getgenvar(self): - return rgenop.genconst(self.dblvalue) - def same_constant(self, other): - return isinstance(other, DoubleRedBox) and self.dblvalue == other.dblvalue + return (isinstance(other, DoubleRedBox) and + self.ll_getvalue(lltype.Float) == other.ll_getvalue(lltype.Float)) class AddrRedBox(ConstRedBox): "A red box that contains a constant address." - # xxx the constant genvar needs to preserve the pointer itself! - # for now do it this way, anyway addresses are not the right thing - # GC wise - def __init__(self, adrvalue, genvar): - self.adrvalue = adrvalue - self.genvar = genvar - - def getgenvar(self): - return self.genvar # created eagerly - def same_constant(self, other): - return isinstance(other, AddrRedBox) and self.adrvalue == other.adrvalue + return (isinstance(other, AddrRedBox) and + self.ll_getvalue(llmemory.Address) == other.ll_getvalue(llmemory.Address)) # ____________________________________________________________ @@ -295,7 +273,7 @@ def leave_block_split(jitstate, switchredbox, exitindex, redboxes): if isinstance(switchredbox, IntRedBox): jitstate.curoutgoinglink = rgenop.closeblock1(jitstate.curblock) - return bool(switchredbox.intvalue) + return switchredbox.ll_getvalue(lltype.Bool) else: exitgvar = switchredbox.getgenvar() linkpair = rgenop.closeblock2(jitstate.curblock, exitgvar) @@ -383,12 +361,14 @@ jitstate.setup() return jitstate -def ll_signed_box(jitstate, value): - value = lltype.cast_primitive(lltype.Signed, value) - return ConstRedBox.ll_fromvalue(value) +def ll_int_box(gv): + return IntRedBox(gv) + +def ll_double_box(gv): + return DoubleRedBox(gv) -def ll_adr_box(jitstate, addr, genvar): # xxx - return AddrRedBox(addr, genvar) +def ll_addr_box(gv): + return AddrRedBox(gv) def ll_var_box(jitstate, gv_TYPE): genvar = rgenop.geninputarg(jitstate.curblock, gv_TYPE) Modified: pypy/branch/njriley-trans/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/branch/njriley-trans/pypy/jit/test/test_hint_annotation.py Fri Mar 10 06:12:02 2006 @@ -386,7 +386,7 @@ py.test.raises(HintError, hannotate, ll_getitem_switch, [annmodel.SomePtr(lltype.Ptr(S))]) -def test_invalid_hint_2(): +def undecided_relevance_test_invalid_hint_2(): S = lltype.GcStruct('S', ('x', lltype.Signed)) def ll_getitem_switch(s): if s.x > 0: # variable exitswitch Modified: pypy/branch/njriley-trans/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/branch/njriley-trans/pypy/jit/test/test_hint_timeshift.py Fri Mar 10 06:12:02 2006 @@ -65,11 +65,12 @@ rgenop.constTYPE(TYPE)]) if i in opt_consts: # XXX what should happen here interface wise is unclear if isinstance(lltype.typeOf(llvalue), lltype.Ptr): - box = llinterp.eval_graph(htshift.ll_adr_box_graph, [jitstate, - llmemory.cast_ptr_to_adr(llvalue), - rgenop.genconst(llvalue)]) # xxx + ll_box_graph = htshift.ll_addr_box_graph + elif isinstance(llvalue, float): + ll_box_graph = htshift.ll_double_box_graph else: - box = llinterp.eval_graph(htshift.ll_signed_box_graph, [jitstate, llvalue]) + ll_box_graph = htshift.ll_int_box_graph + box = llinterp.eval_graph(ll_box_graph, [rgenop.genconst(llvalue)]) graph1args.append(box) residual_graph_args.append(llvalue) startblock = llinterp.eval_graph(htshift.ll_end_setup_jitstate_graph, [jitstate]) Modified: pypy/branch/njriley-trans/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/branch/njriley-trans/pypy/jit/test/test_llabstractinterp.py Fri Mar 10 06:12:02 2006 @@ -211,7 +211,7 @@ graph2, insns = abstrinterp(ll_function, [s, 0, 0], [0, 1, 2]) assert insns == {} -def test_recursive_call(): +def no_longer_relevant_test_recursive_call(): py.test.skip("reimplement or remove the test: " "non-inlined calls with constant results") def ll_factorial(k): Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/computationspace.py Fri Mar 10 06:12:02 2006 @@ -1,29 +1,53 @@ # TODO -# * support several distribution strategies -# * add a linear constraint solver (vital for fast +# * [1] adapt other distribution strategies +# * [5] add a linear constraint solver (vital for fast # constraint propagation over finite integer domains) -# * make all propagators live in their own threads and +# and other kinds of specialized propagators +# * [9] make all propagators live in their own threads and # be awakened by variable/domains events + +# Gert Smolka in +# http://www.cetic.be/moz2004/talks/MOZ2004.pdf : +# * Abandon Logic Variables +# * can be bound everywhere +# * malicious consummer can bind tail variable of stream +# * break abstractions +# * unification not needed +# * Have Futures instead +# * Multilisp [Halstead 85] +# * added to Mozart in 1998 +# * refine logic variable into +# * consummer end (future) +# * producer end (promise) +# * dataflow synchronization + by-need synchronization + + from threading import Thread, Condition, RLock, local -from state import Succeeded, Distributable, Failed, Unknown +from state import Succeeded, Distributable, Failed, \ + Unknown, Forsaken -from variable import EqSet, Var, NoValue, NoDom, \ - VariableException, NotAVariable, AlreadyInStore +from variable import EqSet, CsVar, NoValue, NoDom, \ + VariableException, NotAVariable, AlreadyInStore, \ + AlreadyBound, SimpleVar from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor +import event # NewSpace, Clone, Revise -class Alternatives(object): +class Alternative(object): - def __init__(self, nb_alternatives): - self._nbalt = nb_alternatives + def __init__(self, choices): + self._choices = choices def __eq__(self, other): if other is None: return False - if not isinstance(other, Alternatives): return False - return self._nbalt == other._nbalt + if not isinstance(other, Alternative): return False + return self._choices == other._choices + + def __str__(self): + return "Alternatives(%s)" % self._choices def NoProblem(): """the empty problem, used by clone()""" @@ -69,55 +93,59 @@ # we have to enforce only one distributor # thread running in one space at the same time _nb_choices = 0 + _id_count = 0 def __init__(self, problem, parent=None): + self.id = ComputationSpace._id_count + ComputationSpace._id_count += 1 + self.status = Unknown # consistency-preserving stuff self.in_transaction = False self.bind_lock = RLock() self.var_lock = RLock() - self.dist_lock = RLock() self.distributor = DefaultDistributor(self) - self.status = Unknown + # parent/children self.parent = parent self.children = set() + # mapping from domains to variables + self.doms = {} + # set of all constraints + self.constraints = set() + # mapping from vars to constraints + self.var_const_map = {} + self.event_set = set() if parent is None: self.vars = set() # mapping of names to vars (all of them) self.names = {} - # mapping from vars to constraints - self.var_const_map = {} - # mapping from domains to variables - self.doms = {} - # set of all constraints - self.constraints = set() self.root = self.var('__root__') # set up the problem self.bind(self.root, problem(self)) - # check satisfiability of the space self._init_choose_commit() + self.distributor.start() else: + self.parent.children.add(self) + # shared stuff self.vars = parent.vars self.names = parent.names - # we should really copy stuff - self.var_const_map = parent.var_const_map - self.constraints = parent.constraints - self.doms = {} # shall be copied by clone self.root = parent.root - self.status = parent.status + # copied stuff + self.copy_domains(parent) + self.copy_constraints(parent) + # ... + self.status = Unknown self.distributor = parent.distributor.__class__(self) self._init_choose_commit() - self.distributor.start() - def _init_choose_commit(self): # create a unique choice point - # using two vars as channels betwen + # using two spaceless vars as channels betwen # space and distributor threads - self.CHOOSE = self._make_choice_var() - self.STABLE = self._make_stable_var() + self.CHOOSE = SimpleVar() + self.STABLE = SimpleVar() -#-- utilities ------------------------------------------------- +#-- utilities & instrumentation ----------------------------- def __str__(self): ret = ["") return ' '.join(ret) + def __del__(self): + # try to break ref. cycles and help + # threads terminate + self.status = Forsaken + self.parent = None + self.children = None + self.CHOOSE.bind(True) + self.STABLE.bind(True) + + def __eq__(self, spc): + """space equality defined as : + * identity, or + * same set of vars with a domain, and + * same name set, and + * equal domains, and + * same set of constraints, and + * different propagators of the same type""" + if not isinstance(spc, ComputationSpace): return False + if id(self) == id(spc): return True + r1 = self.vars == spc.vars + r2 = self.names == spc.names + r3 = self.constraints != spc.constraints + r4 = self.distributor != spc.distributor + r5 = self.root == spc.root + if not r1 and r2 and r3 and r4 and r5: + return False + # now the domains + it1 = [item for item in self.doms.items() + if item[1] != NoDom] + it2 = [item for item in spc.doms.items() + if item[1] != NoDom] + it1.sort() + it2.sort() + for (v1, d1), (v2, d2) in zip (it1, it2): + if v1 != v2: return False + if d1 != d2: return False + if id(v1) != id(v2): return False + if id(d1) == id(d2): return False + return True + + def __ne__(self, other): + return not self == other + def pretty_doms(self): print "(-- domains --" - for v, d in self.doms.items(): + doms = self.doms.items() + doms.sort() + for v, d in doms: if d != NoDom: - print ' ', str(d) + print ' ', str(d.get_values()) print " -- domains --)" + #-- Computation Space ----------------------------------------- - def _make_choice_var(self): - ComputationSpace._nb_choices += 1 - ch_var = self.var('__choice__'+str(self._nb_choices)) - return ch_var - - def _make_stable_var(self): - ComputationSpace._nb_choices += 1 - st_var = self.var('__stable__'+str(self._nb_choices)) - return st_var + #-- space helpers ----------------------------------------- def _process(self): - """auxilary of the distributor - """ - #XXX: shouldn't only the distributor call it ? - #XXX: this is all sequential, but in the future - # when propagators live in threads and are - # awaken by events on variables, this might - # completely disappear - try: - self.satisfy_all() - except ConsistencyFailure: - self.status = Failed - else: - if self._distributable(): - self.status = Distributable + """wraps the propagator""" + if len(self.event_set): + try: + self.satisfy_all() + except ConsistencyFailure: + self.status = Failed else: - self.status = Succeeded + if not self._distributable(): + self.status = Succeeded def _distributable(self): - self.dist_lock.acquire() - try: - if self.status not in (Failed, Succeeded): - for var in self.root.val: - if self.dom(var).size() > 1 : - return True - return False - finally: - self.dist_lock.release() - # in The Book : "the space has one thread that is - # suspended on a choice point with two or more alternatives. - # A space can have at most one choice point; attempting to - # create another gives an error." + if self.status not in (Failed, Succeeded): + for var in self.root.val: + if self.dom(var).size() > 1 : + return True + return False def top_level(self): return self.parent is None + def _notify(self, event): + self.event_set.add(event) + + #-- space official API ------------------------------------ + def ask(self): - #print "SPACE Ask() checks stability ..." - self.STABLE.get() # that's real stability - #print "SPACE is stable, resuming Ask()" + self.STABLE.get() status = self.status in (Failed, Succeeded) if status: return self.status if self._distributable(): - return Alternatives(self.distributor.nb_subdomains()) + return Alternative(self.distributor.nb_subdomains()) + # should be unreachable print "DOMS", [(var, self.doms[var]) for var in self.vars @@ -197,11 +252,13 @@ raise NotImplementedError def clone(self): - #XXX: lazy copy of domains would be nice + # did you ask before ... ? + assert self.STABLE.is_bound() spc = ComputationSpace(NoProblem, parent=self) - for var in spc.vars: - if self.dom(var) != NoDom: - spc.set_dom(var, self.dom(var).copy()) + print "-- cloning %s to %s --" % (self.id, spc.id) + self._notify(event.Clone) + spc._process() + spc.distributor.start() return spc def inject(self, restricting_problem): @@ -216,14 +273,10 @@ some_number must satisfy 1= 0: + print "history size (%s) : %s" % (space.id, ldh) + last = domain_history[-1] else: - return iffalse + curr = [(item[0], len(item[1].get_values())) + for item in space.doms.items() + if item[1] != NoDom] + curr.sort() + print "(diff -- v : d 0 (%s)" % space.id + for l in curr: + print ' '*6, '%s : %2d' % (l[0], l[1]) + print " --)" + return + curr = [(item[0], len(item[1].get_values())) + for item in space.doms.items() + if item[1] != NoDom] + curr.sort() + print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, space.id) + for l1, l2 in zip(last, curr): + print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1]) + print " --)" Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/constraint.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/constraint.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/constraint.py Fri Mar 10 06:12:02 2006 @@ -18,7 +18,6 @@ """Implements the functionnality related to the changed flag. Can be used as a starting point for concrete domains""" - #__implements__ = DomainInterface def __init__(self): self.__changed = 0 @@ -40,44 +39,24 @@ Variable Domain with a finite set of possible values """ - _copy_count = 0 - _write_count = 0 - def __init__(self, values): """values is a list of values in the domain This class uses a dictionnary to make sure that there are no duplicate values""" AbstractDomain.__init__(self) - if isinstance(values,FiniteDomain): - # do a copy on write - self._cow = True - values._cow = True - FiniteDomain._copy_count += 1 - self._values = values._values - else: - # don't check this there (a) - #assert len(values) > 0 - self.set_values(values) - - ##self.getValues = self._values.keys + self.set_values(values) def set_values(self, values): - self._cow = False - FiniteDomain._write_count += 1 self._values = set(values) def remove_value(self, value): """Remove value of domain and check for consistency""" ## print "removing", value, "from", self._values.keys() - if self._cow: - self.set_values(self._values) del self._values[value] self._value_removed() def remove_values(self, values): """Remove values of domain and check for consistency""" - if self._cow: - self.set_values(self._values) if values: ## print "removing", values, "from", self._values.keys() for val in values : @@ -103,7 +82,7 @@ return FiniteDomain(self) def __repr__(self): - return '' % str(self.get_values()) + return '' % str(self.get_values()) def __eq__(self, other): if other is NoDom: return False @@ -131,18 +110,24 @@ self._names_to_vars[var.name] = var self._variables = variables - def affectedVariables(self): + def affected_variables(self): """ Return a list of all variables affected by this constraint """ return self._variables def isVariableRelevant(self, variable): return variable in self._variables - def estimateCost(self): + def estimate_cost(self): """Return an estimate of the cost of the narrowing of the constraint""" return reduce(operator.mul, [self.cs.dom(var).size() for var in self._variables]) + def copy_to(self, space): + return self.__class__(space, self._variables) + + def __eq__(self, other): #FIXME and parent + if not isinstance(other, self.__class__): return False + return self._variables == other._variables class BasicConstraint(object): """A BasicConstraint, which is never queued by the Repository @@ -159,6 +144,9 @@ def __repr__(self): return '<%s %s %s>'% (self.__class__, self._variable, self._reference) + def copy_to(self, space): + raise NotImplementedError + def isVariableRelevant(self, variable): return variable == self._variable @@ -184,6 +172,8 @@ repr(self)) return 1 + def __eq__(self, other): + raise NotImplementedError def make_lambda_head(vars): var_ids = ','.join([var.name for var in vars]) @@ -211,6 +201,11 @@ + expand_expr_template(formula, variables), {}, {}) Expression._FILTER_CACHE[formula] = self.filterFunc + + def copy_to(self, space): + return self.__class__(space, self._variables, + self.formula, self.type) + def _init_result_cache(self): """key = (variable,value), value = [has_success,has_failure]""" result_cache = {} @@ -248,7 +243,7 @@ def revise3(self): # removed domain arg. (auc, ale) - """generic narrowing algorithm for n-ary expressions""" + """generic propagation algorithm for n-ary expressions""" maybe_entailed = 1 ffunc = self.filterFunc result_cache = self._init_result_cache() @@ -264,6 +259,7 @@ result_cache[var][val] = 1 else: maybe_entailed = 0 + try: for var, keep in result_cache.iteritems(): domain = self.cs.dom(self._names_to_vars[var]) @@ -278,6 +274,13 @@ return maybe_entailed + def __eq__(self, other): + if not super(Expression, self).__eq__(other): return False + r1 = self.formula == other.formula + r2 = self.type == other.type + return r1 and r2 + + def __repr__(self): return '<%s>' % self.formula @@ -291,6 +294,9 @@ assert len(variables) == 2 Expression.__init__(self, variables, formula, type) + def copy_to(self, space): + raise NotImplementedError + def revise3(self, domains): """specialized narrowing algorithm for binary expressions Runs much faster than the generic version""" Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/distributor.py Fri Mar 10 06:12:02 2006 @@ -1,6 +1,8 @@ import math, random from threading import Thread -from state import Succeeded, Distributable, Failed +from state import Succeeded, Distributable, Failed, Forsaken +from event import Revise +from variable import SimpleVar def arrange_domains(cs, variables): """build a data structure from var to dom @@ -95,7 +97,7 @@ class RandomizingDistributor(AbstractDistributor): - """distributes domains as the NaiveDistrutor, except that the unique + """distributes domains as the NaiveDistributor, except that the unique value of the first domain is picked at random.""" def _distribute(self, dom1, dom2): @@ -138,22 +140,26 @@ ### new threaded distributor def run(self): - self.cs._process() # propagate first - self.cs.STABLE.bind(0) + print "-- distributor started (%s) --" % self.cs.id + assert not self.cs.STABLE.is_bound() + #XXX: are the domains properly set up ? + #self.cs._process() # propagate first + #better let clone() do this call while self.cs._distributable(): + self.cs.STABLE.bind(True) choice = self.cs.choose(self.nb_subdomains()) - # racey ... ? + if self.cs.status == Forsaken: + print "-- distributor (%s) ready for GC --" % self.cs.id + break + print "-- distribution & propagation (%s) --" % self.cs.id self.distribute(choice-1) self.cs._process() - old_choose_var = self.cs.CHOOSE - self.cs.CHOOSE = self.cs._make_choice_var() - self.cs._del_var(old_choose_var) - self.cs.STABLE.bind(0) # unlocks Ask - print "-- distributor terminated --" + self.cs.CHOOSE = SimpleVar() + self.cs.STABLE.bind(True) # unlocks Ask + print "-- distributor terminated (%s) --" % self.cs.id def distribute(self, choice): - """See AbstractDistributor""" variable = self.findSmallestDomain() #variables = self.cs.get_variables_with_a_domain() #domains = arrange_domains(self.cs, variables) @@ -164,6 +170,7 @@ int(math.floor((choice + 1) * nb_elts))) self.cs.dom(variable).remove_values(values[:start]) self.cs.dom(variable).remove_values(values[end:]) + self.cs._notify(Revise(variable)) class DichotomyDistributor(SplitDistributor): Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/problems.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/problems.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/problems.py Fri Mar 10 06:12:02 2006 @@ -11,8 +11,8 @@ cs = computation_space x, y, z = cs.var('x'), cs.var('y'), cs.var('z') cs.set_dom(x, c.FiniteDomain([-4, -2, -1, 0, 1, 2, 4])) - cs.set_dom(y, c.FiniteDomain([0, 2, 3, 4, 5, 16])) - cs.set_dom(z, c.FiniteDomain([-2, -1, 0, 1, 2])) + cs.set_dom(y, c.FiniteDomain([0, 1, 2, 4, 8, 16])) + cs.set_dom(z, c.FiniteDomain([0, 1, 2])) cs.add_constraint([x, y, z], 'y==x**2-z') # set up a distribution strategy cs.set_distributor(di.DichotomyDistributor(cs)) @@ -114,4 +114,35 @@ for conf2 in variables: if conf2 > conf1: cs.add_constraint([conf1,conf2], '%s != %s'%(conf1.name,conf2.name)) + + return tuple(variables) + +def sudoku(computation_space): + cs = computation_space + import constraint as c + + variables = [cs.var('v%i%i'%(x,y)) for x in range(1,10) for y in range(1,10)] + + # Make the variables + for v in variables: + cs.set_dom(v, c.FiniteDomain(range(1,10))) + # Add constraints for rows (sum should be 45) + for i in range(1,10): + row = [ v for v in variables if v.name[1] == str(i)] + cs.add_constraint(row, 'sum([%s]) == 45' % ', '.join([v.name for v in row])) + # Add constraints for columns (sum should be 45) + for i in range(1,10): + row = [ v for v in variables if v.name[2] == str(i)] + cs.add_constraint(row, 'sum([%s]) == 45' % ', '.join([v.name for v in row])) + # Add constraints for subsquares (sum should be 45) + offsets = [(r,c) for r in [-1,0,1] for c in [-1,0,1]] + subsquares = [(r,c) for r in [2,5,8] for c in [2,5,8]] + for rc in subsquares: + sub = [cs.get_var_by_name('v%d%d'% (rc[0] + off[0],rc[1] + off[1])) for off in offsets] + cs.add_constraint(sub, 'sum([%s]) == 45' % ', '.join([v.name for v in sub])) + for v in sub: + for m in sub[sub.index(v)+1:]: + cs.add_constraint([v,m], '%s != %s' % (v.name, m.name)) + #print cs.constraints return tuple(variables) + Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/state.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/state.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/state.py Fri Mar 10 06:12:02 2006 @@ -11,4 +11,4 @@ class Unknown: pass - +class Forsaken: pass Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/strategies.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/strategies.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/strategies.py Fri Mar 10 06:12:02 2006 @@ -15,11 +15,12 @@ return None elif status == csp.Succeeded: return space - elif status == csp.Alternatives(2): + elif status == csp.Alternative(2): new_space = space.clone() space.commit(1) outcome = do_dfs(space) if outcome is None: + new_space.ask() new_space.commit(2) return do_dfs(new_space) else: @@ -50,12 +51,14 @@ if status == csp.Succeeded: print ' '*len(sp_stack), "solution !" solutions.append(space) - elif status == csp.Alternatives(2): + elif status == csp.Alternative(2): print ' '*len(sp_stack), "branches ..." sp1 = space.clone() + sp1.ask() sp1.commit(1) sp_stack.append(sp1) sp2 = space.clone() + sp2.ask() sp2.commit(2) sp_stack.append(sp2) Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_computationspace.py Fri Mar 10 06:12:02 2006 @@ -484,48 +484,63 @@ assert set(['x', 'y', 'z']) == \ set([var.name for var in spc.root.val]) - def test_ask_success(self): - spc = newspace(problems.one_solution_problem) - assert spc.ask() == space.Succeeded - assert spc.ask() == space.Succeeded +# we need to carefully craft some noop problems +# for these tests +# also what is tested below is tested in other places +# so me might want to just forget about it + +## def test_ask_success(self): +## spc = newspace(problems.one_solution_problem) +## assert spc.ask() == space.Succeeded +## assert spc.ask() == space.Succeeded - def test_ask_failure(self): - spc = newspace(problems.unsatisfiable_problem) - assert spc.ask() == space.Failed +## def test_ask_failure(self): +## spc = newspace(problems.unsatisfiable_problem) +## assert spc.ask() == space.Failed def test_ask_alternatives(self): spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) - def test_clone_and_process(self): - spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternatives(2) - new_spc = spc.clone() - assert new_spc.parent == spc - assert new_spc.vars == spc.vars - assert new_spc.names == spc.names - assert new_spc.root == spc.root - assert new_spc.constraints == spc.constraints - assert new_spc.distributor != spc.distributor - it1 = [item for item in spc.doms.items() - if item[1] != space.NoDom] - it2 = [item for item in new_spc.doms.items() - if item[1] != space.NoDom] - it1.sort() - it2.sort() - for (v1, d1), (v2, d2) in zip (it1, it2): - assert v1 == v2 - assert d1 == d2 - assert id(v1) == id(v2) - assert id(d1) != id(d2) - # following couple of ops superceeded by inject() - x, y, z = new_spc.find_vars('x', 'y', 'z') - new_spc.add_constraint([x], 'x == 0') - new_spc.add_constraint([z, y], 'z == y') - new_spc.add_constraint([y], 'y < 2') - new_spc._process() - assert spc.ask() == space.Alternatives(2) - assert new_spc.ask() == space.Succeeded +## def test_clone_and_process(self): +## spc = newspace(problems.satisfiable_problem) +## assert spc.ask() == space.Alternative(2) +## new_spc = spc.clone() +## #assert spc == new_spc +## assert new_spc.parent == spc +## # following couple of ops superceeded by inject() +## x, y, z = new_spc.find_vars('x', 'y', 'z') +## new_spc.add_constraint([x], 'x == 0') +## new_spc.add_constraint([z, y], 'z == y') +## new_spc.add_constraint([y], 'y < 2') +## new_spc._process() +## assert spc.ask() == space.Alternative(2) +## assert new_spc.ask() == space.Succeeded + + def test_clone(self): + """checks that a chain of initially s1 = s2 + s1 - commit(1) - commit(1) ... + s2 - clone - commit(1) - clone - commit(1) ... + converges toward the same solution + """ + s1 = newspace(problems.conference_scheduling) + s2 = s1 + + def eager_and(t1, t2): + return t1 and t2 + + while not (eager_and(s2.ask() == space.Succeeded, + s1.ask() == space.Succeeded)): + #print "S1", s1.pretty_doms() + #print "S2", s2.pretty_doms() + #assert s1 == s2 + temp = s2.clone() + temp.ask() + assert temp.parent is s2 + assert temp in s2.children + s2 = temp + s1.commit(1) + s2.commit(1) def test_inject(self): def more_constraints(space): @@ -535,49 +550,81 @@ space.add_constraint([y], 'y < 2') spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) new_spc = spc.clone() + new_spc.ask() new_spc.inject(more_constraints) - assert spc.ask() == space.Alternatives(2) + assert spc.ask() == space.Alternative(2) assert new_spc.ask() == space.Succeeded def test_merge(self): - spc = newspace(problems.satisfiable_problem) - x, y, z = spc.find_vars('x', 'y', 'z') - print spc.doms - assert spc.top_level() - assert spc.dom(x) == c.FiniteDomain([-4, -2, -1, 0, - 1, 2, 4]) - assert spc.dom(y) == c.FiniteDomain([0, 2, 3, - 4, 5, 16]) - assert spc.dom(z) == c.FiniteDomain([-2, -1, 0, - 1, 2]) - def more_constraints(space): - x, y, z = space.find_vars('x', 'y', 'z') - space.add_constraint([x], '3 > x > 1') - space.add_constraint([z, y], 'z == -1') - space.add_constraint([y], 'y == 3') - - nspc = spc.clone() - nspc.inject(more_constraints) - x, y, z = nspc.find_vars('x', 'y', 'z') - assert not nspc.top_level() - for v in nspc.vars: print v, "==", v.val, nspc.dom(v) - assert nspc.dom(x) == c.FiniteDomain([2]) - assert nspc.dom(y) == c.FiniteDomain([3]) - assert nspc.dom(z) == c.FiniteDomain([-1]) - assert nspc.ask() == space.Succeeded - nspc.merge() - assert x.val == 2 - assert y.val == 3 - assert z.val == -1 - assert (x, y, z) == nspc.root.val + x, y, z = new_spc.find_vars('x', 'y', 'z') + space.add_constraint([x], 'x == 0') + space.add_constraint([z, y], 'z == y') + space.add_constraint([y], 'y < 2') - def test_scheduling_problem_dfs_one_solution(self): + spc = newspace(problems.satisfiable_problem) + assert spc.ask() == space.Alternative(2) + new_spc = spc.clone() + new_spc.ask() + new_spc.inject(more_constraints) + assert spc.ask() == space.Alternative(2) + assert new_spc.ask() == space.Succeeded + x, y, z = new_spc.find_vars('x', 'y', 'z') + res = new_spc.merge() + assert res.values() == [0, 0, 0] + + def test_scheduling_dfs_one_solution(self): sol = strategies.dfs_one(problems.conference_scheduling) - sol2 = [var.val for var in sol] + vars = sol.keys() + vars.sort() + sols = [ sol[k] for k in vars ] + result = [('room A', 'day 1 PM'), + ('room A', 'day 2 AM'), + ('room C', 'day 2 PM'), + ('room C', 'day 2 AM'), + ('room C', 'day 1 AM'), + ('room C', 'day 1 PM'), + ('room B', 'day 2 AM'), + ('room B', 'day 1 AM'), + ('room B', 'day 2 PM'), + ('room A', 'day 1 AM'), + ] + + for v, r1, r2 in zip(vars, sols, result): + print v, r1, r2 + assert sols == result + + + def test_scheduling_all_solutions(self): + sols = strategies.solve_all(problems.conference_scheduling) + assert len(sols) == 64 + print sols + + def no_test_sudoku(self): + #spc = newspace(problems.sudoku) + #print spc.constraints + def more_constraints(space): + f = 'puzzle1.su' + + file = open(f) + c = [] + row = 1 + for line in file.readlines(): + for col in range(1,10): + if line[col-1] != ' ': + tup = ('v%d%d' % (col, row), int(line[col-1])) + space.add_constraint([space.get_var_by_name(tup[0])],'%s == %d' % tup) + row += 1 + + #nspc = spc.clone() + #nspc.inject(more_constraints) + #print nspc.constraints + sol2 = strategies.dfs_one(strategies.sudoku) + print "done dfs" + #sol2 = [var.val for var in sol] assert sol2 == [('room A', 'day 1 PM'), ('room B', 'day 2 PM'), ('room C', 'day 2 AM'), @@ -590,9 +637,4 @@ ('room A', 'day 1 AM')] - - def test_scheduling_problem_all_solutions(self): - sols = strategies.solve_all(problems.conference_scheduling) - assert len(sols) == 64 - Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/test_variable.py Fri Mar 10 06:12:02 2006 @@ -41,7 +41,52 @@ #-- meat ---------------------------- -class TestVariable: +class TestSimpleVariable: + + def test_basics(self): + x = v.SimpleVar() + assert x.val == v.NoValue + x.bind(42) + assert x.val == 42 + x.bind(42) + raises(v.AlreadyBound, x.bind, 43) + + def test_dataflow(self): + def fun(thread, var): + thread.state = 1 + v = var.get() + thread.state = v + + x = v.SimpleVar() + t = FunThread(fun, x) + import time + t.start() + time.sleep(.5) + assert t.state == 1 + x.bind(42) + t.join() + assert t.state == 42 + + def test_stream(self): + def consummer(thread, S): + v = S.get() + if v: + thread.res += v[0] + consummer(thread, v[1]) + + S = v.SimpleVar() + t = FunThread(consummer, S) + t.res = 0 + t.start() + for i in range(10): + tail = v.SimpleVar() + S.bind((i, tail)) + S = tail + S.bind(None) + t.join() + assert t.res == 45 + +class TestCsVariable: def test_no_same_name(self): sp = newspace() Modified: pypy/branch/njriley-trans/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/computation_space/variable.py Fri Mar 10 06:12:02 2006 @@ -1,4 +1,5 @@ import threading +import time #----------- Exceptions --------------------------------- class VariableException(Exception): @@ -9,6 +10,16 @@ def __str__(self): return "%s already in store" % self.name +class AlreadyBound(Exception): + def __init__(self, var, val): + self.var = var + self.val = val + + def __str__(self): + return "%s:%s already bound to %s" % (self.var.name, + self.var.val, + self.val) + class NotAVariable(VariableException): def __str__(self): return "%s is not a variable" % self.name @@ -20,8 +31,74 @@ class NoDom: pass -class Var(object): - """Single-assignment variable""" +class SimpleVar(object): + """Spaceless dataflow variable""" + + def __init__(self): + self.name = str(id(self)) + self._val = NoValue + # a condition variable for concurrent access + self._value_condition = threading.Condition() + + # value accessors + def _set_val(self, val): + self._value_condition.acquire() + try: + if self._val != NoValue: + if val != self._val: + raise AlreadyBound(self, val) + self._val = val + self._value_condition.notifyAll() + finally: + self._value_condition.release() + + def _get_val(self): + return self._val + val = property(_get_val, _set_val) + + + # public interface + + def is_bound(self): + return self.val != NoValue + + def bind(self, val): + self.val = val + + def get(self): + """Make threads wait on the variable + being bound in the top-level space + """ + try: + self._value_condition.acquire() + while not self.is_bound(): + t1 = time.time() + self._value_condition.wait(80) + t2 = time.time() + if t2-t1>80: + raise RuntimeError("possible deadlock??") + return self.val + finally: + self._value_condition.release() + + + def reset(self): + self._value_condition.acquire() + self._val = NoValue + self._value_condition.release() + + +class StreamVar(object): + def __init__(self): + self.var = SimpleVar() + + def bind( self, val ): + newvar = SimpleVar() + self.var.bind( (val, newvar) ) + + +class CsVar(SimpleVar): + """Dataflow variable linked to a space""" def __init__(self, name, cs): if name in cs.names: @@ -56,13 +133,15 @@ # value accessors def _set_val(self, val): self._value_condition.acquire() - if self._cs.in_transaction: - if not self._changed: - self._previous = self._val - self._changed = True - self._val = val - self._value_condition.notifyAll() - self._value_condition.release() + try: + if self._cs.in_transaction: + if not self._changed: + self._previous = self._val + self._changed = True + self._val = val + self._value_condition.notifyAll() + finally: + self._value_condition.release() def _get_val(self): return self._val @@ -76,34 +155,8 @@ def __repr__(self): return self.__str__() - def __eq__(self, thing): - return isinstance(thing, Var) \ - and self.name == thing.name - - def __hash__(self): - return self.name.__hash__() - def bind(self, val): - """top-level space bind""" + """home space bind""" self._cs.bind(self, val) is_bound = _is_bound - - - #-- Dataflow ops with concurrent semantics ------ - # should be used by threads that want to block on - # unbound variables - - def get(self): - """Make threads wait on the variable - being bound in the top-level space - """ - try: - self._value_condition.acquire() - while not self._is_bound(): - self._value_condition.wait() - return self.val - finally: - self._value_condition.release() - - Modified: pypy/branch/njriley-trans/pypy/lib/logic/oz-dataflow-concurrency.txt ============================================================================== --- pypy/branch/njriley-trans/pypy/lib/logic/oz-dataflow-concurrency.txt (original) +++ pypy/branch/njriley-trans/pypy/lib/logic/oz-dataflow-concurrency.txt Fri Mar 10 06:12:02 2006 @@ -1,15 +1,18 @@ -Some rough notes about the Oz threading model -============================================= +==================================================================== +Some rough notes about the Oz threading model and dataflow variables +==================================================================== (almost verbatim from CTM) +Threads +======= + Scheduling ---------- Fair scheduling through round-robin. -Needs not be deterministic (would be nice, especially when debugging, -but probably impossible to achieve). +Needs not be deterministic. With priority levels : three queues exist, which manage high, medium, low priority threads. The time slice ratio for these is @@ -77,9 +80,9 @@ The combination of threads and dataflow variables leads to implicit synchronization : that means synchronization is not textually visible -in the source code but follow from the semantics of dataflow variables -; using such a variable implies synchronization on the variable being -bound to a value. +in the source code but follow from the semantics of dataflow +variables; using such a variable implies synchronization on the +variable being bound to a value. Eager execution (the mere fact of executing statements as they present themselves to the interpreter, withou delay) plus dataflow vars also @@ -94,7 +97,7 @@ values can be seen as complete values that are only partially known"). Dataflow variables ------------------- +================== (see http://www.sics.se/~frej/flow_java/ for an implementation of dataflow variables in Java). @@ -121,3 +124,57 @@ values, provided the partial values are compatible (unifiable) with each other. +Futures +======= + +Dataflow variables are but one technique to implement dataflow +execution. Another, quite popular technique is based on a slightly +different concept, the single-assignment variable. Two of the +best-known instances of the single-assignment variable are futures and +I-structures. The purpose of futures and I-structures is to increase +the potential parallelism of a program by removing inessential +dependencies between calculations. They allow concurrency between a +computation that calculates a value and one that uses the value. This +concurrency can be exploited on a parallel machine. We define futures +and I-structures and compare them with dataflow variables. + +Futures were first introduced in Multilisp, a language intended for +writting parallel programs. Multilisp introduces the function call +(future E) where E is any expression. This does two things: it +immediately returns a placeholder for the result of E and it initiates +a concurrent evaluation of E. When the value of E is needed, i.e., a +computation tries to access the placeholder, then the computation +blocks until the value is available. We model this as follows in the +declarative concurrent model (where E is a zero-argument function) : + +fun {Future E} +X in + thread X={E} end + !!X +end + +A future can only be bound by the concurrent computation that is +created along with it. This is enforced by returning a read-only +variable. Multilisp also has a delay construct that does not initiate +any evaluation but uses by-need execution. It causes evaluation of its +argument only when the result is needed. An I-structure (for +"incomplete structure") is an array of single-assignment +variables. Individual elements can be accessed before the elements are +computed. I-structures were introduced as a language construct for +writing parallel programs in dataflow machines, e.g., in the dataflow +language Id. I-structures are also used in pH ("parallel Haskell"), a +recent language design that extends Haskell for implicit +parallelism. An I-structure permits concurrency between a computation +that calculates the array elements and a computation that uses their +values. When the value of an element is needed, then the computatio +blocks until it is available. Like a future and a read-only variable, +an element of an I-structure can only be bound by the computation that +calculates it. There is a fundamental difference between dataflow +variables on one side and futures and I-structures on the other +side. The latter can be bound only once, whereas dataflow variables +can be bound more than once, as long as the bindings are consistent +with each other. Two partial values are consistent if they are +unifiable. A dataflow variable can be bound many times to different +partial values as long as the partial values are unifiable. + + Modified: pypy/branch/njriley-trans/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/__builtin__/__init__.py (original) +++ pypy/branch/njriley-trans/pypy/module/__builtin__/__init__.py Fri Mar 10 06:12:02 2006 @@ -27,6 +27,8 @@ # is still needed and should stay where it is. 'min' : 'app_functional.min', 'max' : 'app_functional.max', + 'all' : 'app_functional.all', + 'any' : 'app_functional.any', 'enumerate' : 'app_functional.enumerate', 'xrange' : 'app_functional.xrange', 'sorted' : 'app_functional.sorted', Modified: pypy/branch/njriley-trans/pypy/module/__builtin__/app_functional.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/__builtin__/app_functional.py (original) +++ pypy/branch/njriley-trans/pypy/module/__builtin__/app_functional.py Fri Mar 10 06:12:02 2006 @@ -258,6 +258,26 @@ def __iter__(self): return self +# ____________________________________________________________ + +def all( it ): + """ + Implementation of the all() builtin function from 2.5. + """ + for i in it: + if not i: + return False + return True + +def any( it ): + """ + Implementation of the all() builtin function from 2.5. + """ + for i in it: + if i: + return True + return False + # ____________________________________________________________ Modified: pypy/branch/njriley-trans/pypy/module/__builtin__/test/test_functional.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/__builtin__/test/test_functional.py (original) +++ pypy/branch/njriley-trans/pypy/module/__builtin__/test/test_functional.py Fri Mar 10 06:12:02 2006 @@ -7,7 +7,7 @@ assert map(lambda x: x+2, [1, 2, 3, 4]) == [3, 4, 5, 6] def test_trivial_map_two_seq(self): - assert map(lambda x,y: x+y, + assert map(lambda x,y: x+y, [1, 2, 3, 4],[1, 2, 3, 4]) == ( [2, 4, 6, 8]) @@ -16,23 +16,23 @@ def test_trivial_map_no_arguments(self): raises(TypeError, map) - + def test_trivial_map_no_function_no_seq(self): raises(TypeError, map, None) def test_trivial_map_no_fuction_one_seq(self): assert map(None, [1, 2, 3]) == [1, 2, 3] - + def test_trivial_map_no_function(self): assert map(None, [1,2,3], [4,5,6], [7,8], [1]) == ( [(1, 4, 7, 1), (2, 5, 8, None), (3, 6, None, None)]) - + def test_map_identity1(self): a = ['1', 2, 3, 'b', None] b = a[:] assert map(lambda x: x, a) == a assert a == b - + def test_map_None(self): a = ['1', 2, 3, 'b', None] b = a[:] @@ -72,7 +72,7 @@ def test_sum(self): assert reduce(lambda x, y: x+y, [1,2,3,4], 0) == 10 assert reduce(lambda x, y: x+y, [1,2,3,4]) == 10 - + def test_minus(self): assert reduce(lambda x, y: x-y, [10, 2, 8]) == 0 assert reduce(lambda x, y: x-y, [2, 8], 10) == 0 @@ -86,7 +86,7 @@ assert filter(None, txt) == txt tup = ("a", None, 0, [], 1) assert filter(None, tup) == ("a", 1) - + def test_function(self): assert filter(lambda x: x != "a", "a small text") == " smll text" @@ -131,3 +131,54 @@ assert len(r) == 0 assert list(reversed(list(reversed("hello")))) == ['h','e','l','l','o'] raises(TypeError, reversed, reversed("hello")) + + +class AppTestAllAny: + """ + These are copied directly and replicated from the Python 2.5 source code. + """ + + def test_all(self): + + class TestFailingBool: + def __nonzero__(self): + raise RuntimeError + class TestFailingIter: + def __iter__(self): + raise RuntimeError + + assert all([2, 4, 6]) == True + assert all([2, None, 6]) == False + raises(RuntimeError, all, [2, TestFailingBool(), 6]) + raises(RuntimeError, all, TestFailingIter()) + raises(TypeError, all, 10) # Non-iterable + raises(TypeError, all) # No args + raises(TypeError, all, [2, 4, 6], []) # Too many args + assert all([]) == True # Empty iterator + S = [50, 60] + assert all(x > 42 for x in S) == True + S = [50, 40, 60] + assert all(x > 42 for x in S) == False + + def test_any(self): + + class TestFailingBool: + def __nonzero__(self): + raise RuntimeError + class TestFailingIter: + def __iter__(self): + raise RuntimeError + + assert any([None, None, None]) == False + assert any([None, 4, None]) == True + raises(RuntimeError, any, [None, TestFailingBool(), 6]) + raises(RuntimeError, all, TestFailingIter()) + raises(TypeError, any, 10) # Non-iterable + raises(TypeError, any) # No args + raises(TypeError, any, [2, 4, 6], []) # Too many args + assert any([]) == False # Empty iterator + S = [40, 60, 30] + assert any(x > 42 for x in S) == True + S = [10, 20, 30] + assert any(x > 42 for x in S) == False + Modified: pypy/branch/njriley-trans/pypy/module/recparser/pyparser.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/recparser/pyparser.py (original) +++ pypy/branch/njriley-trans/pypy/module/recparser/pyparser.py Fri Mar 10 06:12:02 2006 @@ -10,7 +10,7 @@ from pypy.interpreter.pyparser.syntaxtree import TokenNode, SyntaxNode, AbstractSyntaxVisitor from pypy.interpreter.pyparser.pythonutil import PYTHON_PARSER from pypy.interpreter.pyparser.error import SyntaxError -from pypy.interpreter.pyparser import grammar, pysymbol, pytoken +from pypy.interpreter.pyparser import grammar, symbol, pytoken from pypy.interpreter.argument import Arguments @@ -94,14 +94,14 @@ Returns true if the root node in the syntax tree is an expr node, false otherwise. """ - return self.node.name == pysymbol.eval_input + return self.node.name == symbol.eval_input def issuite(self): """STType.issuite() Returns true if the root node in the syntax tree is a suite node, false otherwise. """ - return self.node.name == pysymbol.file_input + return self.node.name == symbol.file_input def descr_compile(self, w_filename = ""): """STType.compile() @@ -226,8 +226,8 @@ def descr_grammarelement_repr( self, space ): """TODO: make __repr__ RPython""" - import pysymbol - return space.wrap( self.display(0, pysymbol.sym_name) ) + import symbol + return space.wrap( self.display(0, symbol.sym_name) ) def descr_grammarelement_get_children( self, space ): return space.newlist( [ space.wrap(it) for it in self.args ] ) Modified: pypy/branch/njriley-trans/pypy/module/stackless/test/test_interp_coroutine.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/stackless/test/test_interp_coroutine.py (original) +++ pypy/branch/njriley-trans/pypy/module/stackless/test/test_interp_coroutine.py Fri Mar 10 06:12:02 2006 @@ -209,3 +209,81 @@ data = wrap_stackless_function(f) assert int(data.strip()) == 4711 + +def test_tree_compare(): + class Node: + def __init__(self, value, left=None, right=None): + self.value = value + self.left = left + self.right = right + def __repr__(self): + return 'Node(%r, %r, %r)'%(self.value, self.left, self.right) + + tree1 = Node(1, Node(2, Node(3))) + tree2 = Node(1, Node(3, Node(2))) + tree3 = Node(1, Node(2), Node(3)) + + class Super: + pass + class Producer(Super): + def __init__(self, tree, objects, consumer): + self.tree = tree + self.objects = objects + self.consumer = consumer + def produce(self, t): + if t is None: + return + self.objects.append(t.value) + self.consumer.switch() + self.produce(t.left) + self.produce(t.right) + def call(self): + self.produce(self.tree) + while 1: + self.consumer.switch() + class Consumer(Super): + def __init__(self, tree, objects, producer): + self.tree = tree + self.objects = objects + self.producer = producer + def consume(self, t): + if t is None: + return True + self.producer.switch() + if not self.objects: + return False + if self.objects.pop(0) != t.value: + return False + if not self.consume(t.left): + return False + return self.consume(t.right) + + def call(self): + self.result = self.consume(self.tree) + costate.main.switch() + + def pre_order_eq(t1, t2): + objects = [] + producer = Coroutine() + consumer = Coroutine() + + producer.bind(Producer(t1, objects, consumer)) + cons = Consumer(t2, objects, producer) + consumer.bind(cons) + + consumer.switch() + + return cons.result + + def ep(): + return "%d %d %d %d"%(pre_order_eq(tree1, tree2), + pre_order_eq(tree1, tree1), + pre_order_eq(tree1, tree3), + pre_order_eq(tree2, tree1), + + ) + + output = wrap_stackless_function(ep) + assert output.strip() == '0 1 1 0' + + Modified: pypy/branch/njriley-trans/pypy/module/symbol/__init__.py ============================================================================== --- pypy/branch/njriley-trans/pypy/module/symbol/__init__.py (original) +++ pypy/branch/njriley-trans/pypy/module/symbol/__init__.py Fri Mar 10 06:12:02 2006 @@ -21,10 +21,10 @@ # Export the values from our custom symbol module. # Skip negative values (the corresponding symbols are not visible in # pure Python). -from pypy.interpreter.pyparser import pysymbol +from pypy.interpreter.pyparser.pythonparse import PYTHON_PARSER sym_name = {} -for val, name in pysymbol._cpython_symbols.sym_name.items(): +for val, name in PYTHON_PARSER.symbols.sym_name.items(): if val >= 0: Module.interpleveldefs[name] = 'space.wrap(%d)' % val sym_name[val] = name Modified: pypy/branch/njriley-trans/pypy/objspace/flow/model.py ============================================================================== --- pypy/branch/njriley-trans/pypy/objspace/flow/model.py (original) +++ pypy/branch/njriley-trans/pypy/objspace/flow/model.py Fri Mar 10 06:12:02 2006 @@ -171,7 +171,7 @@ self.exc_handler = False # block at the start of exception handling code def at(self): - if self.operations: + if self.operations and self.operations[0].offset >= 0: return "@%d" % self.operations[0].offset else: return "" Modified: pypy/branch/njriley-trans/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/branch/njriley-trans/pypy/objspace/flow/objspace.py (original) +++ pypy/branch/njriley-trans/pypy/objspace/flow/objspace.py Fri Mar 10 06:12:02 2006 @@ -508,8 +508,12 @@ the func_closure of a function object.""" # yuk! this is all I could come up with that works in Python 2.2 too class X(object): + def __cmp__(self, other): + self.other = other + return 0 def __eq__(self, other): self.other = other + return True x = X() x_cell, = (lambda: x).func_closure x_cell == c Modified: pypy/branch/njriley-trans/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/branch/njriley-trans/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/branch/njriley-trans/pypy/objspace/flow/test/test_objspace.py Fri Mar 10 06:12:02 2006 @@ -4,6 +4,7 @@ from pypy.interpreter.argument import Arguments from pypy.translator.simplify import simplify_graph from pypy.objspace.flow import FlowObjSpace +from pypy.objspace.flow import objspace import os import operator @@ -641,3 +642,14 @@ def user_defined_function(): pass + + +def test_extract_cell_content(): + class Strange(object): + def __cmp__(self, other): + assert False, "should not be called" + strange = Strange() + def f(): + return strange + res = objspace.extract_cell_content(f.func_closure[0]) + assert res is strange Modified: pypy/branch/njriley-trans/pypy/rpython/callparse.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/callparse.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/callparse.py Fri Mar 10 06:12:02 2006 @@ -26,18 +26,21 @@ getrinputs(rtyper, graph), getrresult(rtyper, graph)) -def callparse(rtyper, graph, hop, opname): +def callparse(rtyper, graph, hop, opname, is_method=False): """Parse the arguments of 'hop' when calling the given 'graph'. """ rinputs = getrinputs(rtyper, graph) space = RPythonCallsSpace() def args_h(start): - return [VarHolder(i, hop.args_s[i]) for i in range(start, hop.nb_args)] + return [VarHolder(i, hop.args_s[i]) + for i in range(start, hop.nb_args)] + start = 1 - is_method if opname == "simple_call": - arguments = Arguments(space, args_h(1)) + arguments = Arguments(space, args_h(start)) elif opname == "call_args": - arguments = Arguments.fromshape(space, hop.args_s[1].const, # shape - args_h(2)) + arguments = Arguments.fromshape(space, + hop.args_s[start].const, # shape + args_h(start+1)) # parse the arguments according to the function we are calling signature = graph.signature defs_h = [] Modified: pypy/branch/njriley-trans/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/llinterp.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/llinterp.py Fri Mar 10 06:12:02 2006 @@ -256,9 +256,25 @@ # if these special cases pile up, do something better here if operation.opname in ['cast_pointer', 'ooupcast', 'oodowncast', 'cast_adr_to_ptr']: vals.insert(0, operation.result.concretetype) - retval = ophandler(*vals) + try: + retval = ophandler(*vals) + except LLException: + self.handle_cleanup(operation, exception=True) + raise + else: + self.handle_cleanup(operation) self.setvar(operation.result, retval) + def handle_cleanup(self, operation, exception=False): + cleanup = getattr(operation, 'cleanup', None) + if cleanup is not None: + cleanup_finally, cleanup_except = cleanup + for op in cleanup_finally: + self.eval_operation(op) + if exception: + for op in cleanup_except: + self.eval_operation(op) + def make_llexception(self, exc=None): if exc is None: original = sys.exc_info() @@ -744,6 +760,9 @@ assert isinstance(INST, ootype.Instance) return ootype.new(INST) + def op_runtimenew(self, class_): + return ootype.runtimenew(class_) + def op_oosetfield(self, inst, name, value): assert isinstance(inst, ootype._instance) assert isinstance(name, str) @@ -776,11 +795,16 @@ assert isinstance(inst, ootype._instance) return bool(inst) - def op_oois(self, inst1, inst2): - assert isinstance(inst1, ootype._instance) - assert isinstance(inst2, ootype._instance) - return inst1 == inst2 # NB. differently-typed NULLs must be equal - + def op_oois(self, obj1, obj2): + if isinstance(obj1, ootype._instance): + assert isinstance(obj2, ootype._instance) + return obj1 == obj2 # NB. differently-typed NULLs must be equal + elif isinstance(obj1, ootype._class): + assert isinstance(obj2, ootype._class) + return obj1 is obj2 + else: + assert False, "oois on something silly" + def op_instanceof(self, inst, INST): return ootype.instanceof(inst, INST) @@ -790,11 +814,6 @@ def op_subclassof(self, class1, class2): return ootype.subclassof(class1, class2) - def op_oosameclass(self, class1, class2): - assert isinstance(class1, ootype._class) - assert isinstance(class2, ootype._class) - return class1 is class2 - def op_ooidentityhash(self, inst): return ootype.ooidentityhash(inst) Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/exceptiondata.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/exceptiondata.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/exceptiondata.py Fri Mar 10 06:12:02 2006 @@ -4,25 +4,12 @@ from pypy.rpython.lltypesystem.lltype import \ Array, malloc, Ptr, PyObject, pyobjectptr, \ FuncType, functionptr, Signed +from pypy.rpython.exceptiondata import AbstractExceptionData from pypy.rpython.extfunctable import standardexceptions from pypy.annotation.classdef import FORCE_ATTRIBUTES_INTO_CLASSES -class ExceptionData: +class ExceptionData(AbstractExceptionData): """Public information for the code generators to help with exceptions.""" - standardexceptions = standardexceptions - - def __init__(self, rtyper): - self.make_standard_exceptions(rtyper) - # (NB. rclass identifies 'Exception' and 'object') - r_type = rclass.getclassrepr(rtyper, None) - r_instance = rclass.getinstancerepr(rtyper, None) - r_type.setup() - r_instance.setup() - self.r_exception_type = r_type - self.r_exception_value = r_instance - self.lltype_of_exception_type = r_type.lowleveltype - self.lltype_of_exception_value = r_instance.lowleveltype - def make_helpers(self, rtyper): # create helper functionptrs @@ -31,14 +18,6 @@ self.fn_pyexcclass2exc = self.make_pyexcclass2exc(rtyper) self.fn_raise_OSError = self.make_raise_OSError(rtyper) - - def make_standard_exceptions(self, rtyper): - bk = rtyper.annotator.bookkeeper - for cls in self.standardexceptions: - classdef = bk.getuniqueclassdef(cls) - rclass.getclassrepr(rtyper, classdef).setup() - - def make_exception_matcher(self, rtyper): # ll_exception_matcher(real_exception_vtable, match_exception_vtable) s_typeptr = annmodel.SomePtr(self.lltype_of_exception_type) Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/llmemory.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/llmemory.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/llmemory.py Fri Mar 10 06:12:02 2006 @@ -89,6 +89,20 @@ def set(self, ob, value): raise Exception("can't assign to an array's items") +class ArrayLengthOffset(AddressOffset): + + def __init__(self, TYPE): + self.TYPE = TYPE + + def __repr__(self): + return '< ArrayLengthOffset >' + + def get(self, ob): + return len(ob) + + def set(self, ob, value): + raise Exception("can't assign to an array's length") + def sizeof(TYPE, n=None): if n is None: Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/lltype.py Fri Mar 10 06:12:02 2006 @@ -64,6 +64,8 @@ def __ne__(self, other): return not (self == other) + _is_compatible = __eq__ + def __hash__(self): # cannot use saferecursive() -- see test_lltype.test_hash(). # NB. the __cached_hash should neither be used nor updated @@ -738,7 +740,12 @@ def __len__(self): if isinstance(self._T, Array): + if self._T._hints.get('nolength', False): + raise TypeError("%r instance has no length attribute" % + (self._T,)) + return len(self._obj.items) + raise TypeError("%r instance is not an array" % (self._T,)) def __repr__(self): @@ -1095,6 +1102,7 @@ return result def isCompatibleType(TYPE1, TYPE2): + return TYPE1._is_compatible(TYPE2) return TYPE1 == TYPE2 # mark type ADT methods @@ -1102,5 +1110,30 @@ def typeMethod(func): func._type_method = True return func - +def dissect_ll_instance(v, t=None, memo=None): + if memo is None: + memo = {} + if id(v) in memo: + return + memo[id(v)] = True + if t is None: + t = typeOf(v) + yield t, v + if isinstance(t, Ptr): + if v._obj: + for i in dissect_ll_instance(v._obj, t.TO, memo): + yield i + elif isinstance(t, Struct): + parent = v._parentstructure() + if parent: + for i in dissect_ll_instance(parent, typeOf(parent), memo): + yield i + for n in t._flds: + f = getattr(t, n) + for i in dissect_ll_instance(getattr(v, n), t._flds[n], memo): + yield i + elif isinstance(t, Array): + for item in v.items: + for i in dissect_ll_instance(item, t.OF, memo): + yield i Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rclass.py Fri Mar 10 06:12:02 2006 @@ -224,6 +224,8 @@ return llops.genop('cast_pointer', [vcls], resulttype=self.lowleveltype) + fromclasstype = fromtypeptr + def getclsfield(self, vcls, attr, llops): """Read the given attribute of 'vcls'.""" if attr in self.clsfields: @@ -366,32 +368,14 @@ def getflavor(self): return self.classdef.classdesc.read_attribute('_alloc_flavor_', Constant('gc')).value - def convert_const(self, value): - if value is None: - return nullptr(self.object_type) - if isinstance(value, types.MethodType): - value = value.im_self # bound method -> instance - cls = value.__class__ - bk = self.rtyper.annotator.bookkeeper - classdef = bk.getdesc(cls).getuniqueclassdef() - if classdef != self.classdef: - # if the class does not match exactly, check that 'value' is an - # instance of a subclass and delegate to that InstanceRepr - if classdef.commonbase(self.classdef) != self.classdef: - raise TyperError("not an instance of %r: %r" % ( - self.classdef.name, value)) - rinstance = getinstancerepr(self.rtyper, classdef) - result = rinstance.convert_const(value) - return cast_pointer(self.lowleveltype, result) - # common case - try: - return self.prebuiltinstances[id(value)][1] - except KeyError: - self.setup() - result = malloc(self.object_type, flavor=self.getflavor()) # pick flavor - self.prebuiltinstances[id(value)] = value, result - self.initialize_prebuilt_instance(value, classdef, result) - return result + def null_instance(self): + return nullptr(self.object_type) + + def upcast(self, result): + return cast_pointer(self.lowleveltype, result) + + def create_instance(self): + return malloc(self.object_type, flavor=self.getflavor()) # pick flavor def get_ll_eq_function(self): return ll_inst_eq Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/rpbc.py Fri Mar 10 06:12:02 2006 @@ -7,12 +7,13 @@ typeOf, Void, ForwardReference, Struct, Bool, \ Ptr, malloc, nullptr from pypy.rpython.rmodel import Repr, TyperError, inputconst, inputdesc -from pypy.rpython.rmodel import warning, mangle, CanBeNull from pypy.rpython import robject from pypy.rpython import rtuple -from pypy.rpython.rpbc import SingleFrozenPBCRepr, samesig,\ - commonbase, allattributenames, FunctionsPBCRepr, \ - AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr +from pypy.rpython.rpbc import samesig,\ + commonbase, allattributenames, adjust_shape, \ + AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr, \ + AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ + AbstractFunctionsPBCRepr from pypy.rpython.lltypesystem import rclass from pypy.tool.sourcetools import has_varargs @@ -26,7 +27,7 @@ # ____________________________________________________________ -class MultipleFrozenPBCRepr(CanBeNull, Repr): +class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr): """Representation selected for multiple non-callable pre-built constants.""" def __init__(self, rtyper, access_set): self.rtyper = rtyper @@ -36,159 +37,38 @@ self.pbc_cache = {} def _setup_repr(self): - llfields = [] - llfieldmap = {} - if self.access_set is not None: - attrlist = self.access_set.attrs.keys() - attrlist.sort() - for attr in attrlist: - s_value = self.access_set.attrs[attr] - r_value = self.rtyper.getrepr(s_value) - mangled_name = mangle('pbc', attr) - llfields.append((mangled_name, r_value.lowleveltype)) - llfieldmap[attr] = mangled_name, r_value + llfields = self._setup_repr_fields() self.pbc_type.become(Struct('pbc', *llfields)) - self.llfieldmap = llfieldmap - def convert_desc(self, frozendesc): - if (self.access_set is not None and - frozendesc not in self.access_set.descs): - raise TyperError("not found in PBC access set: %r" % (frozendesc,)) - try: - return self.pbc_cache[frozendesc] - except KeyError: - self.setup() - result = malloc(self.pbc_type, immortal=True) - self.pbc_cache[frozendesc] = result - for attr, (mangled_name, r_value) in self.llfieldmap.items(): - if r_value.lowleveltype is Void: - continue - try: - thisattrvalue = frozendesc.read_attribute(attr) - except AttributeError: - warning("Desc %r has no attribute %r" % (frozendesc, attr)) - continue - llvalue = r_value.convert_const(thisattrvalue) - setattr(result, mangled_name, llvalue) - return result - - def convert_const(self, pbc): - if pbc is None: - return nullptr(self.pbc_type) - if isinstance(pbc, types.MethodType) and pbc.im_self is None: - value = pbc.im_func # unbound method -> bare function - frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc) - return self.convert_desc(frozendesc) - - def rtype_getattr(self, hop): - attr = hop.args_s[1].const - vpbc, vattr = hop.inputargs(self, Void) - v_res = self.getfield(vpbc, attr, hop.llops) - mangled_name, r_res = self.llfieldmap[attr] - return hop.llops.convertvar(v_res, r_res, hop.r_result) + def create_instance(self): + return malloc(self.pbc_type, immortal=True) + + def null_instance(self): + return nullptr(self.pbc_type) def getfield(self, vpbc, attr, llops): - mangled_name, r_value = self.llfieldmap[attr] + mangled_name, r_value = self.fieldmap[attr] cmangledname = inputconst(Void, mangled_name) return llops.genop('getfield', [vpbc, cmangledname], resulttype = r_value) -class __extend__(pairtype(MultipleFrozenPBCRepr, MultipleFrozenPBCRepr)): - def convert_from_to((r_pbc1, r_pbc2), v, llops): - if r_pbc1.access_set == r_pbc2.access_set: - return v - return NotImplemented - -class __extend__(pairtype(SingleFrozenPBCRepr, MultipleFrozenPBCRepr)): - def convert_from_to((r_pbc1, r_pbc2), v, llops): - frozendesc1 = r_pbc1.frozendesc - access = frozendesc1.queryattrfamily() - if access is r_pbc2.access_set: - return inputdesc(r_pbc2, frozendesc1) - return NotImplemented - # ____________________________________________________________ +class FunctionsPBCRepr(AbstractFunctionsPBCRepr): + """Representation selected for a PBC of function(s).""" -class MethodOfFrozenPBCRepr(Repr): - """Representation selected for a PBC of method object(s) of frozen PBCs. - It assumes that all methods are the same function bound to different PBCs. - The low-level representation can then be a pointer to that PBC.""" - - def __init__(self, rtyper, s_pbc): - self.rtyper = rtyper - self.funcdesc = s_pbc.descriptions.keys()[0].funcdesc - - # a hack to force the underlying function to show up in call_families - # (generally not needed, as normalizecalls() should ensure this, - # but needed for bound methods that are ll helpers) - # XXX sort this out - #call_families = rtyper.annotator.getpbccallfamilies() - #call_families.find((None, self.function)) + def setup_specfunc(self): + fields = [] + for row in self.uniquerows: + fields.append((row.attrname, row.fntype)) + return Ptr(Struct('specfunc', *fields)) - if s_pbc.can_be_none(): - raise TyperError("unsupported: variable of type " - "method-of-frozen-PBC or None") - - im_selves = [] - for desc in s_pbc.descriptions: - assert desc.funcdesc is self.funcdesc - im_selves.append(desc.frozendesc) - - self.s_im_self = annmodel.SomePBC(im_selves) - self.r_im_self = rtyper.getrepr(self.s_im_self) - self.lowleveltype = self.r_im_self.lowleveltype - - def get_s_callable(self): - return annmodel.SomePBC([self.funcdesc]) - - def get_r_implfunc(self): - r_func = self.rtyper.getrepr(self.get_s_callable()) - return r_func, 1 - - def convert_desc(self, mdesc): - if mdesc.funcdesc is not self.funcdesc: - raise TyperError("not a method bound on %r: %r" % (self.funcdesc, - mdesc)) - return self.r_im_self.convert_desc(mdesc.frozendesc) - - def convert_const(self, method): - mdesc = self.rtyper.annotator.bookkeeper.getdesc(method) - return self.convert_desc(mdesc) - - def rtype_simple_call(self, hop): - return self.redispatch_call(hop, call_args=False) - - def rtype_call_args(self, hop): - return self.redispatch_call(hop, call_args=True) - - def redispatch_call(self, hop, call_args): - # XXX obscure, try to refactor... - s_function = annmodel.SomePBC([self.funcdesc]) - hop2 = hop.copy() - hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self' - hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self') - if isinstance(hop2.args_v[0], Constant): - boundmethod = hop2.args_v[0].value - hop2.args_v[0] = Constant(boundmethod.im_self) - if call_args: - hop2.swap_fst_snd_args() - _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape - adjust_shape(hop2, s_shape) - # a marker that would crash if actually used... - c = Constant("obscure-don't-use-me") - hop2.v_s_insertfirstarg(c, s_function) # insert 'function' - # now hop2 looks like simple_call(function, self, args...) - return hop2.dispatch() - -def adjust_shape(hop2, s_shape): - new_shape = (s_shape.const[0]+1,) + s_shape.const[1:] - c_shape = Constant(new_shape) - s_shape = hop2.rtyper.annotator.bookkeeper.immutablevalue(new_shape) - hop2.v_s_insertfirstarg(c_shape, s_shape) # reinsert adjusted shape - -# ____________________________________________________________ + def create_specfunc(self): + return malloc(self.lowleveltype.TO, immortal=True) + def get_specfunc_row(self, llop, v, c_rowname, resulttype): + return llop.genop('getfield', [v, c_rowname], resulttype=resulttype) + class MethodsPBCRepr(AbstractMethodsPBCRepr): """Representation selected for a PBC of the form {func: classdef...}. It assumes that all the methods come from the same name in a base @@ -201,7 +81,6 @@ return self.redispatch_call(hop, call_args=True) def redispatch_call(self, hop, call_args): - hop2 = hop.copy() r_class = self.r_im_self.rclass mangled_name, r_func = r_class.clsfields[self.methodname] assert isinstance(r_func, (FunctionsPBCRepr, @@ -214,14 +93,9 @@ v_cls = self.r_im_self.getfield(v_im_self, '__class__', hop.llops) v_func = r_class.getclsfield(v_cls, self.methodname, hop.llops) - hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self' - hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self') - + hop2 = self.add_instance_arg_to_hop(hop, call_args) opname = 'simple_call' if call_args: - hop2.swap_fst_snd_args() - _, s_shape = hop2.r_s_popfirstarg() - adjust_shape(hop2, s_shape) opname = 'call_args' hop2.v_s_insertfirstarg(v_func, s_func) # insert 'function' @@ -275,14 +149,8 @@ assert hop.nb_args == 1, ("arguments passed to __init__, " "but no __init__!") else: - hop2 = hop.copy() - hop2.r_s_popfirstarg() # discard the class pointer argument - if call_args: - _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape - hop2.v_s_insertfirstarg(v_instance, s_instance) # add 'instance' - adjust_shape(hop2, s_shape) - else: - hop2.v_s_insertfirstarg(v_instance, s_instance) # add 'instance' + hop2 = self.replace_class_with_inst_arg( + hop, v_instance, s_instance, call_args) hop2.v_s_insertfirstarg(v_init, s_init) # add 'initfunc' hop2.s_result = annmodel.s_None hop2.r_result = self.rtyper.getrepr(hop2.s_result) Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lloperation.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lloperation.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lloperation.py Fri Mar 10 06:12:02 2006 @@ -11,6 +11,7 @@ name == 'op_subclassof' or name == 'op_instanceof' or name == 'op_classof' or + name == 'op_runtimenew' or name.startswith('op_oo'))] Modified: pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/lltypesystem/test/test_lltype.py Fri Mar 10 06:12:02 2006 @@ -508,3 +508,41 @@ assert typeOf(res) == TGT assert res == expect +def test_array_with_no_length(): + A = GcArray(Signed, hints={'nolength': True}) + a = malloc(A, 10) + py.test.raises(TypeError, len, a) + +def test_dissect_ll_instance(): + assert list(dissect_ll_instance(1)) == [(Signed, 1)] + GcS = GcStruct("S", ('x', Signed)) + s = malloc(GcS) + s.x = 1 + assert list(dissect_ll_instance(s)) == [(Ptr(GcS), s), (GcS, s._obj), (Signed, 1)] + + A = GcArray(('x', Signed)) + a = malloc(A, 10) + for i in range(10): + a[i].x = i + expected = [(Ptr(A), a), (A, a._obj)] + for t in [((A.OF, a._obj.items[i]), (Signed, i)) for i in range(10)]: + expected.extend(t) + assert list(dissect_ll_instance(a)) == expected + + R = GcStruct("R", ('r', Ptr(GcForwardReference()))) + R.r.TO.become(R) + + r = malloc(R) + r.r = r + r_expected = [(Ptr(R), r), (R, r._obj)] + assert list(dissect_ll_instance(r)) == r_expected + + B = GcArray(Ptr(R)) + b = malloc(B, 2) + b[0] = b[1] = r + b_expected = [(Ptr(B), b), (B, b._obj)] + assert list(dissect_ll_instance(b)) == b_expected + r_expected + + memo = {} + assert list(dissect_ll_instance(r, None, memo)) == r_expected + assert list(dissect_ll_instance(b, None, memo)) == b_expected Modified: pypy/branch/njriley-trans/pypy/rpython/memory/gc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/memory/gc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/memory/gc.py Fri Mar 10 06:12:02 2006 @@ -87,7 +87,7 @@ def __init__(self, dummy=None, get_roots=None): self.get_roots = get_roots - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) def malloc(self, typeid, length=0): size = self.fixed_size(typeid) @@ -115,7 +115,7 @@ #need to maintain a list of malloced objects, since we used the systems #allocator and can't walk the heap self.malloced_objects = AddressLinkedList() - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots def malloc(self, typeid, length=0): @@ -127,6 +127,8 @@ size_gc_header = self.size_gc_header() result = raw_malloc(size + size_gc_header) ## print "mallocing %s, size %s at %s" % (typeid, size, result) + if self.is_varsize(typeid): + (result + self.varsize_offset_to_length(typeid)).signed[0] = length self.init_gc_object(result, typeid) self.malloced_objects.append(result) self.bytes_malloced += size + size_gc_header @@ -224,7 +226,7 @@ self.top_of_space = self.tospace + space_size self.fromspace = raw_malloc(space_size) self.free = self.tospace - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots def free_memory(self): @@ -359,7 +361,7 @@ self.zero_ref_counts = AddressLinkedList() self.length_zero_ref_counts = 0 self.max_refcount_zero = max_refcount_zero - self.set_query_functions(None, None, None, None, None, None, None) + #self.set_query_functions(None, None, None, None, None, None, None) self.get_roots = get_roots self.collecting = False Modified: pypy/branch/njriley-trans/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/memory/gctransform.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/memory/gctransform.py Fri Mar 10 06:12:02 2006 @@ -88,10 +88,20 @@ for var in block.inputargs: if var_needsgc(var): newops.extend(self.push_alive(var)) + # XXX this is getting obscure. Maybe we should use the basic + # graph-transforming capabilities of the RTyper instead, as we + # seem to run into all the same problems as the ones we already + # had to solve there. + num_ops_after_exc_raising = 0 for op in block.operations: - ops, cleanup_before_exception = self.replacement_operations(op, livevars) + num_ops_after_exc_raising = 0 + res = self.replacement_operations(op, livevars) + try: + ops, cleanup_before_exception = res + except ValueError: + ops, cleanup_before_exception, num_ops_after_exc_raising = res newops.extend(ops) - op = ops[-1] + op = ops[-1-num_ops_after_exc_raising] # XXX for now we assume that everything can raise if 1 or op.opname in EXCEPTION_RAISING_OPS: if tuple(livevars) in livevars2cleanup: @@ -103,9 +113,12 @@ cleanup_on_exception = tuple(cleanup_on_exception) livevars2cleanup[tuple(livevars)] = cleanup_on_exception op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception + op = ops[-1] if var_needsgc(op.result): if op.opname not in ('direct_call', 'indirect_call') and not var_ispyobj(op.result): - newops.extend(self.push_alive(op.result)) + lst = list(self.push_alive(op.result)) + newops.extend(lst) + num_ops_after_exc_raising += len(lst) livevars.append(op.result) if len(block.exits) == 0: # everything is fine already for returnblocks and exceptblocks @@ -117,6 +130,15 @@ # to the block, even if the variable dies in all # linked blocks. deadinallexits = sets.Set([]) + if num_ops_after_exc_raising > 0: + # No place to put the remaining pending operations! + # Need a new block along the non-exceptional link. + # XXX test this. + tail = newops[-num_ops_after_exc_raising:] + del newops[-num_ops_after_exc_raising:] + link = block.exits[0] + assert link.exitcase is None + insert_empty_block(self.translator, link, tail) else: deadinallexits = sets.Set(livevars) for link in block.exits: @@ -603,36 +625,122 @@ self.finalizer_funcptrs[TYPE] = fptr return fptr + +def gc_pointers_inside(v, adr): + t = lltype.typeOf(v) + if isinstance(t, lltype.Struct): + for n, t2 in t._flds.iteritems(): + if isinstance(t2, lltype.Ptr) and t2._needsgc() and t2.TO != lltype.PyObject: + yield adr + llmemory.offsetof(t, n) + elif isinstance(t2, (lltype.Array, lltype.Struct)): + for a in gc_pointers_inside(getattr(v, n), adr + llmemory.offsetof(t, n)): + yield a + elif isinstance(t, lltype.Array): + if isinstance(t.OF, lltype.Ptr) and t2._needsgc(): + for i in range(len(v.items)): + yield adr + llmemory.itemoffsetof(t, i) + elif isinstance(t.OF, lltype.Struct): + for i in range(len(v.items)): + for a in gc_pointers_inside(v.items[i], adr + llmemory.itemoffsetof(t, i)): + yield a + class FrameworkGCTransformer(BoehmGCTransformer): def __init__(self, translator): super(FrameworkGCTransformer, self).__init__(translator) class GCData(object): + from pypy.rpython.memory.gc import MarkSweepGC as GCClass startheapsize = 640*1024 # XXX adjust rootstacksize = 640*1024 # XXX adjust + + # types of the GC information tables + OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed) + TYPE_INFO = lltype.Struct("type_info", + ("fixedsize", lltype.Signed), + ("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)), + ("varitemsize", lltype.Signed), + ("ofstovar", lltype.Signed), + ("ofstolength", lltype.Signed), + ("varofstoptrs",lltype.Ptr(OFFSETS_TO_GC_PTR)), + ) + TYPE_INFO_TABLE = lltype.Array(TYPE_INFO) + + def q_is_varsize(typeid): + return gcdata.type_info_table[typeid].varitemsize != 0 + + def q_offsets_to_gc_pointers(typeid): + return gcdata.type_info_table[typeid].ofstoptrs + + def q_fixed_size(typeid): + return gcdata.type_info_table[typeid].fixedsize + + def q_varsize_item_sizes(typeid): + return gcdata.type_info_table[typeid].varitemsize + + def q_varsize_offset_to_variable_part(typeid): + return gcdata.type_info_table[typeid].ofstovar + + def q_varsize_offset_to_length(typeid): + return gcdata.type_info_table[typeid].ofstolength + + def q_varsize_offsets_to_gcpointers_in_var_part(typeid): + return gcdata.type_info_table[typeid].varofstoptrs + gcdata = GCData() + # set up dummy a table, to be overwritten with the real one in finish() + gcdata.type_info_table = lltype.malloc(GCData.TYPE_INFO_TABLE, 0, + immortal=True) + gcdata.static_roots = lltype.malloc(lltype.Array(llmemory.Address), 0, + immortal=True) + gcdata.static_root_start = gcdata.static_root_end = llmemory.cast_ptr_to_adr(gcdata.static_roots) + self.gcdata = gcdata + self.type_info_list = [] + self.id_of_type = {} # {LLTYPE: type_id} + self.seen_roots = {} + self.static_gc_roots = [] + self.addresses_of_static_ptrs_in_nongc = [] + self.offsettable_cache = {} + self.malloc_fnptr_cache = {} + sizeofaddr = llmemory.sizeof(llmemory.Address) from pypy.rpython.memory.lladdress import NULL class StackRootIterator: _alloc_flavor_ = 'raw' def __init__(self): - self.current = gcdata.root_stack_top + self.stack_current = gcdata.root_stack_top + self.static_current = gcdata.static_root_start def pop(self): - while self.current != gcdata.root_stack_base: - self.current -= sizeofaddr - result = self.current.address[0] - if result != NULL: - return result + while self.static_current != gcdata.static_root_end: + result = self.static_current + self.static_current += sizeofaddr + if result.address[0].address[0] != NULL: + return result.address[0] + while self.stack_current != gcdata.root_stack_base: + self.stack_current -= sizeofaddr + if self.stack_current.address[0] != NULL: + return self.stack_current return NULL def frameworkgc_setup(): + # run-time initialization code stackbase = lladdress.raw_malloc(GCData.rootstacksize) gcdata.root_stack_top = stackbase gcdata.root_stack_base = stackbase -# from pypy.rpython.memory.gc import MarkSweepGC -# gcdata.gc = MarkSweepGC(GCData.startheapsize, StackRootIterator) + gcdata.gc = GCData.GCClass(GCData.startheapsize, StackRootIterator) + gcdata.gc.set_query_functions( + q_is_varsize, + q_offsets_to_gc_pointers, + q_fixed_size, + q_varsize_item_sizes, + q_varsize_offset_to_variable_part, + q_varsize_offset_to_length, + q_varsize_offsets_to_gcpointers_in_var_part) + i = 0 + while i < len(gcdata.static_roots): + push_root(gcdata.static_roots[i]) + i += 1 def push_root(addr): top = gcdata.root_stack_top @@ -645,6 +753,24 @@ gcdata.root_stack_top = top return result + bk = self.translator.annotator.bookkeeper + + # the point of this little dance is to not annotate + # self.gcdata.type_info_table as a constant. + data_classdef = bk.getuniqueclassdef(GCData) + data_classdef.generalize_attr( + 'type_info_table', + annmodel.SomePtr(lltype.Ptr(GCData.TYPE_INFO_TABLE))) + data_classdef.generalize_attr( + 'static_roots', + annmodel.SomePtr(lltype.Ptr(lltype.Array(llmemory.Address)))) + data_classdef.generalize_attr( + 'static_root_start', + annmodel.SomeAddress()) + data_classdef.generalize_attr( + 'static_root_end', + annmodel.SomeAddress()) + annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper) frameworkgc_setup_graph = annhelper.getgraph(frameworkgc_setup, [], annmodel.s_None) @@ -653,11 +779,20 @@ annmodel.s_None) pop_root_graph = annhelper.getgraph(pop_root, [], annmodel.SomeAddress()) + + classdef = bk.getuniqueclassdef(GCData.GCClass) + s_gcdata = annmodel.SomeInstance(classdef) + malloc_graph = annhelper.getgraph(GCData.GCClass.malloc.im_func, + [s_gcdata, + annmodel.SomeInteger(nonneg=True), + annmodel.SomeInteger(nonneg=True)], + annmodel.SomeAddress()) annhelper.finish() # at this point, annotate all mix-level helpers self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph, attach_empty_cleanup=True) self.push_root_ptr = self.graph2funcptr(push_root_graph) self.pop_root_ptr = self.graph2funcptr(pop_root_graph) + self.malloc_ptr = self.graph2funcptr(malloc_graph, True) def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True @@ -665,6 +800,114 @@ MinimalGCTransformer(self.translator).transform_graph(graph) return const_funcptr_fromgraph(graph) + def get_type_id(self, TYPE): + try: + return self.id_of_type[TYPE] + except KeyError: + assert not self.finished + assert isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)) + # Record the new type_id description as a small dict for now. + # It will be turned into a Struct("type_info") in finish() + type_id = len(self.type_info_list) + info = {} + self.type_info_list.append(info) + self.id_of_type[TYPE] = type_id + offsets = offsets_to_gc_pointers(TYPE) + info["ofstoptrs"] = self.offsets2table(offsets) + if not TYPE._is_varsize(): + info["fixedsize"] = llmemory.sizeof(TYPE) + else: + info["fixedsize"] = llmemory.sizeof(TYPE, 0) + if isinstance(TYPE, lltype.Struct): + ARRAY = TYPE._flds[TYPE._arrayfld] + ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld) + info["ofstolength"] = ofs1 + info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) + else: + ARRAY = TYPE + info["ofstolength"] = llmemory.ArrayLengthOffset(ARRAY) + info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0) + assert isinstance(ARRAY, lltype.Array) + offsets = offsets_to_gc_pointers(ARRAY.OF) + info["varofstoptrs"] = self.offsets2table(offsets) + info["varitemsize"] = llmemory.sizeof(ARRAY.OF) + return type_id + + def consider_constant(self, TYPE, value): + if id(value) not in self.seen_roots: + self.seen_roots[id(value)] = True + if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)): + self.get_type_id(TYPE) + if TYPE != lltype.PyObject and find_gc_ptrs_in_type(TYPE): + if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)): + self.static_gc_roots.append(value) + else: + for a in gc_pointers_inside(value, llmemory.fakeaddress(value)): + self.addresses_of_static_ptrs_in_nongc.append(a) + + def offsets2table(self, offsets): + key = tuple(offsets) + try: + return self.offsettable_cache[key] + except KeyError: + cachedarray = lltype.malloc(self.gcdata.OFFSETS_TO_GC_PTR, + len(offsets), immortal=True) + for i, value in enumerate(offsets): + cachedarray[i] = value + self.offsettable_cache[key] = cachedarray + return cachedarray + + def finish(self): + newgcdependencies = super(FrameworkGCTransformer, self).finish() + if self.type_info_list is not None: + + table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, + len(self.type_info_list), immortal=True) + for tableentry, newcontent in zip(table, self.type_info_list): + for key, value in newcontent.items(): + setattr(tableentry, key, value) + self.type_info_list = None + self.offsettable_cache = None + + # replace the type_info_table pointer in gcdata -- at this point, + # the database is in principle complete, so it has already seen + # the old (empty) array. We need to force it to consider the new + # array now. It's a bit hackish as the old empty array will also + # be generated in the C source, but that's a rather minor problem. + + # XXX because we call inputconst already in replace_malloc, we can't + # modify the instance, we have to modify the 'rtyped instance' + # instead. horrors. is there a better way? + + s_gcdata = self.translator.annotator.bookkeeper.immutablevalue( + self.gcdata) + r_gcdata = self.translator.rtyper.getrepr(s_gcdata) + ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value + ll_instance.inst_type_info_table = table + #self.gcdata.type_info_table = table + + ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address), + len(self.static_gc_roots), + immortal=True) + for i in range(len(self.static_gc_roots)): + c = self.static_gc_roots[i] + ll_static_roots[i] = llmemory.fakeaddress(c) + ll_instance.inst_static_roots = ll_static_roots + + ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address), + len(self.addresses_of_static_ptrs_in_nongc), + immortal=True) + for i in range(len(self.addresses_of_static_ptrs_in_nongc)): + ll_static_roots_inside[i] = self.addresses_of_static_ptrs_in_nongc[i] + ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address)) + ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(ll_static_roots_inside) + + newgcdependencies = newgcdependencies or [] + newgcdependencies.append(table) + newgcdependencies.append(ll_static_roots) + newgcdependencies.append(ll_static_roots_inside) + return newgcdependencies + def protect_roots(self, op, livevars): livevars = [var for var in livevars if not var_ispyobj(var)] newops = list(self.push_roots(livevars)) @@ -673,8 +916,39 @@ replace_direct_call = protect_roots replace_indirect_call = protect_roots - replace_malloc = protect_roots - replace_malloc_varsize = protect_roots + + def replace_malloc(self, op, livevars): + TYPE = op.args[0].value + PTRTYPE = op.result.concretetype + assert PTRTYPE.TO == TYPE + type_id = self.get_type_id(TYPE) + + v = varoftype(llmemory.Address) + c_type_id = rmodel.inputconst(lltype.Signed, type_id) + if len(op.args) == 1: + v_length = rmodel.inputconst(lltype.Signed, 0) + else: + v_length = op.args[1] + + # surely there's a better way of doing this? + s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(self.gcdata) + r_gcdata = self.translator.rtyper.getrepr(s_gcdata) + s_gc = self.translator.annotator.bookkeeper.valueoftype(self.gcdata.GCClass) + r_gc = self.translator.rtyper.getrepr(s_gc) + + newop0 = SpaceOperation( + "getfield", + [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc", lltype.Void)], + varoftype(r_gc.lowleveltype)) + newop = SpaceOperation("direct_call", + [self.malloc_ptr, newop0.result, c_type_id, v_length], + v) + ops, finally_ops = self.protect_roots(newop, livevars) + ops.insert(0, newop0) + ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result)) + return ops, finally_ops, 1 + + replace_malloc_varsize = replace_malloc def push_alive_nopyobj(self, var): return [] @@ -697,6 +971,25 @@ yield SpaceOperation("gc_reload_possibly_moved", [v, var], varoftype(lltype.Void)) +# XXX copied and modified from lltypelayout.py +def offsets_to_gc_pointers(TYPE): + offsets = [] + if isinstance(TYPE, lltype.Struct): + for name in TYPE._names: + FIELD = getattr(TYPE, name) + if isinstance(FIELD, lltype.Array): + continue # skip inlined array + baseofs = llmemory.offsetof(TYPE, name) + suboffsets = offsets_to_gc_pointers(FIELD) + for s in suboffsets: + if s == 0: + offsets.append(baseofs) + else: + offsets.append(baseofs + s) + elif (isinstance(TYPE, lltype.Ptr) and TYPE._needsgc() and + TYPE.TO is not lltype.PyObject): + offsets.append(0) + return offsets # ___________________________________________________________________ # calculate some statistics about the number of variables that need Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/ootype.py Fri Mar 10 06:12:02 2006 @@ -1,19 +1,36 @@ from pypy.rpython.lltypesystem.lltype import LowLevelType, Signed, Unsigned, Float, Char -from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, Primitive -from pypy.rpython.lltypesystem.lltype import frozendict +from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \ + Primitive, isCompatibleType +from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType class OOType(LowLevelType): - pass + + def _is_compatible(TYPE1, TYPE2): + if TYPE1 == TYPE2: + return True + if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): + return isSubclass(TYPE1, TYPE2) + else: + return False class Class(OOType): - pass + + def _defl(self): + return nullruntimeclass + Class = Class() class Instance(OOType): """this is the type of user-defined objects""" - def __init__(self, name, superclass, fields={}, methods={}): + def __init__(self, name, superclass, fields={}, methods={}, + _is_root=False): self._name = name - self._superclass = superclass + + if _is_root: + self._superclass = None + else: + assert isinstance(superclass, Instance) + self._superclass = superclass self._methods = frozendict() self._fields = frozendict() @@ -27,8 +44,7 @@ def _defl(self): return self._null - def _example(self): - return new(self) + def _example(self): return new(self) def __repr__(self): return '<%s>' % (self,) @@ -118,6 +134,7 @@ all.update(self._fields) return all + class StaticMethod(OOType): __slots__ = ['_null'] @@ -129,6 +146,9 @@ def _example(self): _retval = self.RESULT._example() return _static_meth(self, _callable=lambda *args: _retval) + + def _defl(self): + return null(self) class Meth(StaticMethod): @@ -162,7 +182,7 @@ def __setattr__(self, name, value): self.__getattr__(name) - if self._TYPE._field_type(name) != typeOf(value): + if not isCompatibleType(typeOf(value), self._TYPE._field_type(name)): raise TypeError("Expected type %r" % self._TYPE._field_type(name)) self.__dict__[name] = value @@ -325,14 +345,6 @@ c = c._superclass return None -def isCompatibleType(TYPE1, TYPE2): - if TYPE1 == TYPE2: - return True - if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): - return isSubclass(TYPE1, TYPE2) - else: - return False - def ooupcast(INSTANCE, instance): assert instanceof(instance, INSTANCE) return instance @@ -347,3 +359,6 @@ return id(inst) else: return 0 # for all null instances + + +ROOT = Instance('Root', None, _is_root=True) Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rbuiltin.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rbuiltin.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rbuiltin.py Fri Mar 10 06:12:02 2006 @@ -10,11 +10,23 @@ return hop.genop('new', vlist, resulttype = hop.r_result.lowleveltype) +def rtype_null(hop): + assert hop.args_s[0].is_constant() + TYPE = hop.args_s[0].const + nullvalue = ootype.null(TYPE) + return hop.inputconst(TYPE, nullvalue) + def rtype_classof(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOInstance) return hop.genop('classof', hop.args_v, resulttype = ootype.Class) +def rtype_subclassof(hop): + assert isinstance(hop.args_s[0], annmodel.SomeOOClass) + assert isinstance(hop.args_s[1], annmodel.SomeOOClass) + return hop.genop('subclassof', hop.args_v, + resulttype = ootype.Bool) + def rtype_runtimenew(hop): assert isinstance(hop.args_s[0], annmodel.SomeOOClass) return hop.genop('runtimenew', hop.args_v, @@ -40,7 +52,7 @@ v_obj, v_cls = hop.inputargs(instance_repr, class_repr) if isinstance(v_cls, Constant): - c_cls = hop.inputconst(ootype.Void, v_cls.value._INSTANCE) + c_cls = hop.inputconst(ootype.Void, v_cls.value.class_._INSTANCE) return hop.genop('instanceof', [v_obj, c_cls], resulttype=ootype.Bool) else: raise TyperError("XXX missing impl of isinstance(x, variable)") @@ -48,7 +60,9 @@ BUILTIN_TYPER = {} BUILTIN_TYPER[ootype.new] = rtype_new +BUILTIN_TYPER[ootype.null] = rtype_null BUILTIN_TYPER[ootype.classof] = rtype_classof +BUILTIN_TYPER[ootype.subclassof] = rtype_subclassof BUILTIN_TYPER[ootype.runtimenew] = rtype_runtimenew BUILTIN_TYPER[ootype.ooidentityhash] = rtype_ooidentityhash BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rclass.py Fri Mar 10 06:12:02 2006 @@ -1,46 +1,140 @@ import types from pypy.annotation import model as annmodel from pypy.annotation import description +from pypy.objspace.flow import model as flowmodel from pypy.rpython.rmodel import inputconst, TyperError +from pypy.rpython.rmodel import mangle as pbcmangle from pypy.rpython.rclass import AbstractClassRepr, AbstractInstanceRepr, \ getinstancerepr, getclassrepr, get_type_repr from pypy.rpython.ootypesystem import ootype from pypy.annotation.pairtype import pairtype from pypy.tool.sourcetools import func_with_new_name -CLASSTYPE = ootype.Class +CLASSTYPE = ootype.Instance("Object_meta", ootype.ROOT, + fields={"class_": ootype.Class}) +OBJECT = ootype.Instance("Object", ootype.ROOT, + fields={'meta': CLASSTYPE}) + class ClassRepr(AbstractClassRepr): def __init__(self, rtyper, classdef): AbstractClassRepr.__init__(self, rtyper, classdef) - self.lowleveltype = ootype.Class + if self.classdef is not None: + self.rbase = getclassrepr(self.rtyper, self.classdef.basedef) + base_type = self.rbase.lowleveltype + self.lowleveltype = ootype.Instance( + self.classdef.name + "_meta", base_type) + else: + # we are ROOT + self.lowleveltype = CLASSTYPE def _setup_repr(self): - pass # not actually needed? + clsfields = {} + pbcfields = {} + if self.classdef is not None: + # class attributes + llfields = [] + """ + attrs = self.classdef.attrs.items() + attrs.sort() + for name, attrdef in attrs: + if attrdef.readonly: + s_value = attrdef.s_value + s_unboundmethod = self.prepare_method(s_value) + if s_unboundmethod is not None: + allmethods[name] = True + s_value = s_unboundmethod + r = self.rtyper.getrepr(s_value) + mangled_name = 'cls_' + name + clsfields[name] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + """ + # attributes showing up in getattrs done on the class as a PBC + extra_access_sets = self.rtyper.class_pbc_attributes.get( + self.classdef, {}) + for access_set, counter in extra_access_sets.items(): + for attr, s_value in access_set.attrs.items(): + r = self.rtyper.getrepr(s_value) + mangled_name = pbcmangle('pbc%d' % counter, attr) + pbcfields[access_set, attr] = mangled_name, r + llfields.append((mangled_name, r.lowleveltype)) + + self.rbase.setup() + ootype.addFields(self.lowleveltype, dict(llfields)) + #self.clsfields = clsfields + self.pbcfields = pbcfields + self.meta_instance = None + + def get_meta_instance(self, cast_to_root_meta=True): + if self.meta_instance is None: + self.meta_instance = ootype.new(self.lowleveltype) + self.setup_meta_instance(self.meta_instance, self) + + meta_instance = self.meta_instance + if cast_to_root_meta: + meta_instance = ootype.ooupcast(CLASSTYPE, meta_instance) + return meta_instance - def getruntime(self): - return getinstancerepr(self.rtyper, self.classdef).lowleveltype._class + def setup_meta_instance(self, meta_instance, rsubcls): + if self.classdef is None: + rinstance = getinstancerepr(self.rtyper, rsubcls.classdef) + setattr(meta_instance, 'class_', rinstance.lowleveltype._class) + else: + # setup class attributes: for each attribute name at the level + # of 'self', look up its value in the subclass rsubcls + def assign(mangled_name, value): + if isinstance(value, flowmodel.Constant) and isinstance(value.value, staticmethod): + value = flowmodel.Constant(value.value.__get__(42)) # staticmethod => bare function + llvalue = r.convert_desc_or_const(value) + setattr(meta_instance, mangled_name, llvalue) + + #mro = list(rsubcls.classdef.getmro()) + #for fldname in self.clsfields: + # mangled_name, r = self.clsfields[fldname] + # if r.lowleveltype is Void: + # continue + # value = rsubcls.classdef.classdesc.read_attribute(fldname, None) + # if value is not None: + # assign(mangled_name, value) + # extra PBC attributes + for (access_set, attr), (mangled_name, r) in self.pbcfields.items(): + if rsubcls.classdef.classdesc not in access_set.descs: + continue # only for the classes in the same pbc access set + if r.lowleveltype is ootype.Void: + continue + attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None) + if attrvalue is not None: + assign(mangled_name, attrvalue) + + # then initialize the 'super' portion of the vtable + meta_instance_super = ootype.ooupcast( + self.rbase.lowleveltype, meta_instance) + self.rbase.setup_meta_instance(meta_instance_super, rsubcls) + + getruntime = get_meta_instance + + def fromclasstype(self, vclass, llops): + return llops.genop('oodowncast', [vclass], + resulttype=self.lowleveltype) + + def getpbcfield(self, vcls, access_set, attr, llops): + if (access_set, attr) not in self.pbcfields: + raise TyperError("internal error: missing PBC field") + mangled_name, r = self.pbcfields[access_set, attr] + v_meta = self.fromclasstype(vcls, llops) + cname = inputconst(ootype.Void, mangled_name) + return llops.genop('oogetfield', [v_meta, cname], resulttype=r) def rtype_issubtype(self, hop): class_repr = get_type_repr(self.rtyper) - vlist = hop.inputargs(class_repr, class_repr) - return hop.genop('subclassof', vlist, resulttype=ootype.Bool) + vmeta1, vmeta2 = hop.inputargs(class_repr, class_repr) + return hop.gendirectcall(ll_issubclass, vmeta1, vmeta2) - - def rtype_is_((r_cls1, r_cls2), hop): - class_repr = get_type_repr(self.rtyper) - vlist = hop.inputargs(class_repr, class_repr) - return hop.genop('oosameclass', vlist, resulttype=ootype.Bool) - - -def rtype_classes_is_(_, hop): - class_repr = get_type_repr(hop.rtyper) - vlist = hop.inputargs(class_repr, class_repr) - return hop.genop('oosameclass', vlist, resulttype=ootype.Bool) - -class __extend__(pairtype(ClassRepr, ClassRepr)): - rtype_is_ = rtype_classes_is_ +def ll_issubclass(meta1, meta2): + class1 = meta1.class_ + class2 = meta2.class_ + return ootype.subclassof(class1, class2) # ____________________________________________________________ @@ -59,16 +153,27 @@ AbstractInstanceRepr.__init__(self, rtyper, classdef) self.baserepr = None - b = self.classdef.basedef - if b is not None: - self.baserepr = getinstancerepr(rtyper, b) - b = self.baserepr.lowleveltype + if self.classdef is None: + self.lowleveltype = OBJECT + else: + b = self.classdef.basedef + if b is not None: + self.baserepr = getinstancerepr(rtyper, b) + b = self.baserepr.lowleveltype + else: + b = OBJECT - self.lowleveltype = ootype.Instance(classdef.shortname, b, {}, {}) + self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}) self.prebuiltinstances = {} # { id(x): (x, _ptr) } self.object_type = self.lowleveltype def _setup_repr(self): + if self.classdef is None: + self.allfields = {} + self.allmethods = {} + self.allclassattributes = {} + return + if self.baserepr is not None: allfields = self.baserepr.allfields.copy() allmethods = self.baserepr.allmethods.copy() @@ -108,7 +213,18 @@ if mangled in allmethods: raise TyperError("class attribute overrides method") allclassattributes[mangled] = name, s_value - + + special_methods = ["__init__", "__del__"] + for meth_name in special_methods: + if meth_name not in selfattrs and \ + self.classdef.classdesc.find_source_for(meth_name) is not None: + s_meth = self.classdef.classdesc.s_get_value(self.classdef, + meth_name) + if isinstance(s_meth, annmodel.SomePBC): + mangled = mangle(meth_name) + allmethods[mangled] = meth_name, s_meth + # else: it's the __init__ of a builtin exception + # # hash() support if self.rtyper.needs_hash_support(self.classdef): @@ -145,9 +261,10 @@ # get method implementation from pypy.rpython.ootypesystem.rpbc import MethodImplementations methimpls = MethodImplementations.get(self.rtyper, s_value) - m = methimpls.get_impl(mangled, methdesc) - - methods[mangled] = m + m_impls = methimpls.get_impl(mangled, methdesc, + is_finalizer=name == "__del__") + + methods.update(m_impls) for classdef in self.classdef.getmro(): @@ -256,7 +373,8 @@ if hop.args_s[0].can_be_none(): return hop.gendirectcall(ll_inst_type, vinst) else: - return hop.genop('classof', [vinst], resulttype=ootype.Class) + cmeta = inputconst(ootype.Void, "meta") + return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE) def rtype_hash(self, hop): if self.classdef is None: @@ -271,46 +389,34 @@ vinst, = hop.inputargs(self) return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed) - def convert_const(self, value): - if value is None: - return ootype.null(self.lowleveltype) - bk = self.rtyper.annotator.bookkeeper - try: - classdef = bk.getuniqueclassdef(value.__class__) - except KeyError: - raise TyperError("no classdef: %r" % (value.__class__,)) - if classdef != self.classdef: - # if the class does not match exactly, check that 'value' is an - # instance of a subclass and delegate to that InstanceRepr - if classdef is None: - raise TyperError("not implemented: object() instance") - if classdef.commonbase(self.classdef) != self.classdef: - raise TyperError("not an instance of %r: %r" % ( - self.classdef.name, value)) - rinstance = getinstancerepr(self.rtyper, classdef) - result = rinstance.convert_const(value) - return ootype.ooupcast(self.lowleveltype, result) - # common case - try: - return self.prebuiltinstances[id(value)][1] - except KeyError: - self.setup() - result = ootype.new(self.object_type) - self.prebuiltinstances[id(value)] = value, result - self.initialize_prebuilt_instance(value, result) - return result + def null_instance(self): + return ootype.null(self.lowleveltype) + + def upcast(self, result): + return ootype.ooupcast(self.lowleveltype, result) + + def create_instance(self): + return ootype.new(self.object_type) def new_instance(self, llops): """Build a new instance, without calling __init__.""" - - return llops.genop("new", + classrepr = getclassrepr(self.rtyper, self.classdef) + v_instance = llops.genop("new", [inputconst(ootype.Void, self.lowleveltype)], self.lowleveltype) - - def initialize_prebuilt_instance(self, value, result): + cmeta = inputconst(ootype.Void, "meta") + cmeta_instance = inputconst(CLASSTYPE, classrepr.get_meta_instance()) + llops.genop("oosetfield", [v_instance, cmeta, cmeta_instance], + resulttype=ootype.Void) + return v_instance + + def initialize_prebuilt_instance(self, value, classdef, result): # then add instance attributes from this level + classrepr = getclassrepr(self.rtyper, self.classdef) for mangled, (oot, default) in self.lowleveltype._allfields().items(): if oot is ootype.Void: llattrvalue = None + elif mangled == 'meta': + llattrvalue = classrepr.get_meta_instance() elif mangled == '_hash_cache_': # hash() support llattrvalue = hash(value) else: @@ -367,7 +473,7 @@ def ll_inst_type(obj): if obj: - return ootype.classof(obj) + return obj.meta else: # type(None) -> NULL (for now) - return ootype.nullruntimeclass + return ootype.null(CLASSTYPE) Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/rpbc.py Fri Mar 10 06:12:02 2006 @@ -1,35 +1,93 @@ -from pypy.rpython.rpbc import AbstractClassesPBCRepr, AbstractMethodsPBCRepr +from pypy.rpython.rmodel import CanBeNull, Repr, inputconst +from pypy.rpython.rpbc import AbstractClassesPBCRepr, AbstractMethodsPBCRepr, \ + AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ + AbstractFunctionsPBCRepr +from pypy.rpython.rclass import rtype_new_instance, getinstancerepr from pypy.rpython.rpbc import get_concrete_calltable -from pypy.rpython.rclass import rtype_new_instance +from pypy.rpython import callparse from pypy.rpython.ootypesystem import ootype -from pypy.rpython.ootypesystem.rclass import ClassRepr, InstanceRepr, mangle -from pypy.rpython.ootypesystem.rclass import rtype_classes_is_ +from pypy.rpython.ootypesystem.rclass import ClassRepr, InstanceRepr +from pypy.rpython.ootypesystem.rclass import mangle +from pypy.annotation import model as annmodel +from pypy.annotation import description from pypy.annotation.pairtype import pairtype +import types + +class FunctionsPBCRepr(AbstractFunctionsPBCRepr): + """Representation selected for a PBC of function(s).""" + + def setup_specfunc(self): + fields = {} + for row in self.uniquerows: + fields[row.attrname] = row.fntype + return ootype.Instance('specfunc', ootype.ROOT, fields) + + def create_specfunc(self): + return ootype.new(self.lowleveltype) + + def get_specfunc_row(self, llop, v, c_rowname, resulttype): + return llop.genop('oogetfield', [v, c_rowname], resulttype=resulttype) + class ClassesPBCRepr(AbstractClassesPBCRepr): + def rtype_simple_call(self, hop): + classdef = hop.s_result.classdef if self.lowleveltype is not ootype.Void: - raise NotImplementedError() + # instantiating a class from multiple possible classes + v_meta = hop.inputarg(self, arg=0) + c_class_ = hop.inputconst(ootype.Void, "class_") + v_class = hop.genop('oogetfield', [v_meta, c_class_], + resulttype=ootype.Class) + resulttype = getinstancerepr(hop.rtyper, classdef).lowleveltype + v_instance = hop.genop('runtimenew', [v_class], resulttype=resulttype) + c_meta = hop.inputconst(ootype.Void, "meta") + hop.genop('oosetfield', [v_instance, c_meta, v_meta], + resulttype=ootype.Void) + else: + # instantiating a single class + v_instance = rtype_new_instance(hop.rtyper, classdef, hop.llops) - classdef = hop.s_result.classdef - v_instance = rtype_new_instance(hop.rtyper, classdef, hop.llops) + inits = [] + for desc in self.s_pbc.descriptions: + if desc.find_source_for('__init__') is not None: + unbound = desc.s_get_value(desc.getuniqueclassdef(), '__init__') + unbound, = unbound.descriptions + bound = unbound.bind_self(desc.getuniqueclassdef()) + inits.append(bound) + + if inits: + s_init = annmodel.SomePBC(inits) + s_instance = annmodel.SomeInstance(classdef) + hop2 = hop.copy() + hop2.r_s_popfirstarg() # discard the class pointer argument + hop2.v_s_insertfirstarg(v_instance, s_init) # add 'instance' + hop2.s_result = annmodel.s_None + hop2.r_result = self.rtyper.getrepr(hop2.s_result) + # now hop2 looks like simple_call(initmeth, args...) + hop2.dispatch() + else: + assert hop.nb_args == 1, ("arguments passed to __init__, " + "but no __init__!") return v_instance + rtype_call_args = rtype_simple_call + +def row_method_name(methodname, rowname): + return "%s_%s" % (methodname, rowname) + class MethodImplementations(object): def __init__(self, rtyper, methdescs): samplemdesc = methdescs.iterkeys().next() concretetable, uniquerows = get_concrete_calltable(rtyper, samplemdesc.funcdesc.getcallfamily()) - self._uniquerows = uniquerows - if len(uniquerows) == 1: - row = uniquerows[0] + self.row_mapping = {} + for row in uniquerows: sample_as_static_meth = row.itervalues().next() SM = ootype.typeOf(sample_as_static_meth) M = ootype.Meth(SM.ARGS[1:], SM.RESULT) # cut self - self.lowleveltype = M - else: - XXX_later + self.row_mapping[row.attrname] = row, M def get(rtyper, s_pbc): lst = list(s_pbc.descriptions) @@ -43,27 +101,58 @@ return methodsimpl get = staticmethod(get) - def get_impl(self, name, methdesc): - M = self.lowleveltype - if methdesc is None: - return ootype.meth(M, _name=name, abstract=True) - else: - impl_graph = self._uniquerows[0][methdesc.funcdesc].graph - return ootype.meth(M, _name=name, graph=impl_graph) - + def get_impl(self, name, methdesc, is_finalizer=False): + impls = {} + flags = {} + if is_finalizer: + flags['finalizer'] = True + for rowname, (row, M) in self.row_mapping.iteritems(): + if methdesc is None: + m = ootype.meth(M, _name=name, abstract=True, **flags) + else: + impl_graph = row[methdesc.funcdesc].graph + m = ootype.meth(M, _name=name, graph=impl_graph, **flags) + derived_name = row_method_name(name, rowname) + impls[derived_name] = m + return impls + class MethodsPBCRepr(AbstractMethodsPBCRepr): def __init__(self, rtyper, s_pbc): AbstractMethodsPBCRepr.__init__(self, rtyper, s_pbc) + sampledesc = s_pbc.descriptions.iterkeys().next() + self.concretetable, _ = get_concrete_calltable(rtyper, + sampledesc.funcdesc.getcallfamily()) def rtype_simple_call(self, hop): - vlist = hop.inputargs(self, *hop.args_r[1:]) - mangled = mangle(self.methodname) - cname = hop.inputconst(ootype.Void, mangled) - return hop.genop("oosend", [cname]+vlist, - resulttype = hop.r_result.lowleveltype) + return self.call("simple_call", hop) + def rtype_call_args(self, hop): + return self.call("call_args", hop) + + def call(self, opname, hop): + bk = self.rtyper.annotator.bookkeeper + args = bk.build_args(opname, hop.args_s[1:]) + args = args.prepend(self.s_im_self) + s_pbc = hop.args_s[0] # possibly more precise than self.s_pbc + descs = [desc.funcdesc for desc in s_pbc.descriptions] + callfamily = descs[0].getcallfamily() + shape, index = description.FunctionDesc.variant_for_call_site( + bk, callfamily, descs, args) + row_of_graphs = callfamily.calltables[shape][index] + anygraph = row_of_graphs.itervalues().next() # pick any witness + hop2 = self.add_instance_arg_to_hop(hop, opname == "call_args") + vlist = callparse.callparse(self.rtyper, anygraph, hop2, opname, + is_method=True) + rresult = callparse.getrresult(self.rtyper, anygraph) + hop.exception_is_here() + mangled = mangle(self.methodname) + row = self.concretetable[shape, index] + derived_mangled = row_method_name(mangled, row.attrname) + cname = hop.inputconst(ootype.Void, derived_mangled) + v = hop.genop("oosend", [cname]+vlist, resulttype=rresult) + return hop.llops.convertvar(v, rresult, hop.r_result) class __extend__(pairtype(InstanceRepr, MethodsPBCRepr)): @@ -71,9 +160,28 @@ def convert_from_to(_, v, llops): return v +class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr): + """Representation selected for multiple non-callable pre-built constants.""" + def __init__(self, rtyper, access_set): + self.rtyper = rtyper + self.access_set = access_set + self.lowleveltype = ootype.Instance('pbc', ootype.ROOT) + self.pbc_cache = {} + + def _setup_repr(self): + fields_list = self._setup_repr_fields() + ootype.addFields(self.lowleveltype, dict(fields_list)) + + def create_instance(self): + return ootype.new(self.lowleveltype) + + def null_instance(self): + return ootype.null(self.lowleveltype) + + def getfield(self, vpbc, attr, llops): + mangled_name, r_value = self.fieldmap[attr] + cmangledname = inputconst(ootype.Void, mangled_name) + return llops.genop('oogetfield', [vpbc, cmangledname], + resulttype = r_value) -class __extend__(pairtype(ClassRepr, ClassesPBCRepr)): - rtype_is_ = rtype_classes_is_ -class __extend__(pairtype(ClassesPBCRepr, ClassRepr)): - rtype_is_ = rtype_classes_is_ Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ooann.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ooann.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ooann.py Fri Mar 10 06:12:02 2006 @@ -5,7 +5,7 @@ def test_simple_new(): - C = Instance("test", None, {'a': Signed}) + C = Instance("test", ROOT, {'a': Signed}) def oof(): c = new(C) @@ -19,7 +19,7 @@ assert s.knowntype == int def test_simple_instanceof(): - C = Instance("test", None, {'a': Signed}) + C = Instance("test", ROOT, {'a': Signed}) def oof(): c = new(C) @@ -32,7 +32,7 @@ assert s.knowntype == bool def test_simple_null(): - I = Instance("test", None, {'a': Signed}) + I = Instance("test", ROOT, {'a': Signed}) def oof(): i = null(I) @@ -45,7 +45,7 @@ assert s == annmodel.SomeOOInstance(I) def test_simple_classof(): - I = Instance("test", None, {'a': Signed}) + I = Instance("test", ROOT, {'a': Signed}) def oof(): i = new(I) @@ -57,8 +57,23 @@ assert s == annmodel.SomeOOClass(I) +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + a = RPythonAnnotator() + s = a.build_types(oof, []) + #a.translator.view() + + assert s == annmodel.SomeBool() + def test_simple_runtimenew(): - I = Instance("test", None, {'a': Signed}) + I = Instance("test", ROOT, {'a': Signed}) def oof(): i = new(I) @@ -73,7 +88,7 @@ assert s == annmodel.SomeOOInstance(I) def test_complex_runtimenew(): - I = Instance("test", None, {'a': Signed}) + I = Instance("test", ROOT, {'a': Signed}) J = Instance("test2", I, {'b': Signed}) K = Instance("test2", I, {'b': Signed}) @@ -94,7 +109,7 @@ assert s == annmodel.SomeOOInstance(I) def test_method(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) M = Meth([C], Signed) def m_(self, other): @@ -114,7 +129,7 @@ assert s.knowntype == int def test_unionof(): - C1 = Instance("C1", None) + C1 = Instance("C1", ROOT) C2 = Instance("C2", C1) C3 = Instance("C3", C1) @@ -158,7 +173,7 @@ assert s == annmodel.SomeOOStaticMeth(F) def test_truth_value(): - C = Instance("C", None) + C = Instance("C", ROOT) def oof(f): if f: c = new(C) Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oopbc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oopbc.py Fri Mar 10 06:12:02 2006 @@ -17,3 +17,67 @@ assert res == 110 res = interpret(f, [False], type_system='ootype') assert res == 221 + +def test_call_classes(): + class A: pass + class B(A): pass + def f(i): + if i == 1: + cls = B + else: + cls = A + return cls() + res = interpret(f, [0], type_system='ootype') + assert ootype.typeOf(res)._name.split(".")[-1] == 'A' + res = interpret(f, [1], type_system='ootype') + assert ootype.typeOf(res)._name.split(".")[-1] == 'B' + +def test_call_classes_init(): + class A: + def __init__(self, a, b=0): + self.a = a + class B(A): + def __init__(self, a): + self.a = a + 1 + def f(i): + if i == 1: + cls = B + else: + cls = A + return cls(a=1).a + res = interpret(f, [0], type_system='ootype') + assert res == 1 + res = interpret(f, [1], type_system='ootype') + assert res == 2 + +def test_method_call_kwds(): + class A: + def m(self, a, b=0, c=0): + return a + b + c + + def f1(): + a = A() + return a.m(1, b=2) + def f2(): + a = A() + return a.m(1, b=2, c=3) + assert 3 == interpret(f1, [], type_system="ootype") + assert 6 == interpret(f2, [], type_system="ootype") + +def test_classes_attribute(): + class A: + a = 3 + class B(A): + a = 2 + def f(i): + if i == 1: + cls = B + else: + cls = A + instance = cls() + return cls.a + res = interpret(f, [0], type_system='ootype') + assert res == 3 + res = interpret(f, [1], type_system='ootype') + assert res == 2 + Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oortype.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oortype.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_oortype.py Fri Mar 10 06:12:02 2006 @@ -16,7 +16,7 @@ return graphof(t, f) def test_simple_class(): - C = Instance("test", None, {'a': Signed}) + C = Instance("test", ROOT, {'a': Signed}) def f(): c = new(C) @@ -27,7 +27,7 @@ assert rettype == C def test_simple_field(): - C = Instance("test", None, {'a': (Signed, 3)}) + C = Instance("test", ROOT, {'a': (Signed, 3)}) def f(): c = new(C) @@ -39,7 +39,7 @@ assert rettype == Signed def test_simple_method(): - C = Instance("test", None, {'a': (Signed, 3)}) + C = Instance("test", ROOT, {'a': (Signed, 3)}) M = Meth([], Signed) def m_(self): return self.a @@ -55,7 +55,7 @@ assert rettype == Signed def test_truth_value(): - C = Instance("C", None) + C = Instance("C", ROOT) NULL = null(C) def oof(f): if f: @@ -72,3 +72,28 @@ assert res is False res = interpret(oof, [False], type_system='ootype') assert res is True + +def test_simple_classof(): + I = Instance("test", ROOT, {'a': Signed}) + + def oof(): + i = new(I) + return classof(i) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Class + +def test_subclassof(): + I = Instance("test", ROOT, {'a': Signed}) + I1 = Instance("test1", I) + + def oof(): + i = new(I) + i1 = new(I1) + return subclassof(classof(i1), classof(i)) + + g = gengraph(oof, []) + rettype = g.getreturnvar().concretetype + assert rettype == Bool + Modified: pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/ootypesystem/test/test_ootype.py Fri Mar 10 06:12:02 2006 @@ -9,11 +9,11 @@ def m_(self, b): return self.a + b m = meth(M, _name="m", _callable=m_) - I = Instance("test", None, {"a": Signed}, {"m": m}) + I = Instance("test", ROOT, {"a": Signed}, {"m": m}) assert type(hash(I)) == int def test_simple_class(): - I = Instance("test", None, {"a": Signed}) + I = Instance("test", ROOT, {"a": Signed}) i = new(I) py.test.raises(TypeError, "i.z") @@ -23,7 +23,7 @@ assert i.a == 3 def test_assign_super_attr(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) D = Instance("test2", C, {}) d = new(D) @@ -33,7 +33,7 @@ assert d.a == 1 def test_runtime_instanciation(): - I = Instance("test", None, {"a": Signed}) + I = Instance("test", ROOT, {"a": Signed}) c = runtimeClass(I) i = runtimenew(c) @@ -41,7 +41,7 @@ assert typeOf(c) == Class def test_classof(): - I = Instance("test", None, {"a": Signed}) + I = Instance("test", ROOT, {"a": Signed}) c = runtimeClass(I) i = new(I) @@ -56,15 +56,15 @@ assert classof(i2) != classof(i) def test_simple_default_class(): - I = Instance("test", None, {"a": (Signed, 3)}) + I = Instance("test", ROOT, {"a": (Signed, 3)}) i = new(I) assert i.a == 3 - py.test.raises(TypeError, "Instance('test', None, {'a': (Signed, 3.0)})") + py.test.raises(TypeError, "Instance('test', ROOT, {'a': (Signed, 3.0)})") def test_simple_null(): - C = Instance("test", None, {"a": Signed}) + C = Instance("test", ROOT, {"a": Signed}) c = null(C) assert typeOf(c) == C @@ -72,9 +72,9 @@ py.test.raises(RuntimeError, "c.a") def test_simple_class_field(): - C = Instance("test", None, {}) + C = Instance("test", ROOT, {}) - D = Instance("test2", None, {"a": C}) + D = Instance("test2", ROOT, {"a": C}) d = new(D) assert typeOf(d.a) == C @@ -82,7 +82,7 @@ assert d.a == null(C) def test_simple_recursive_class(): - C = Instance("test", None, {}) + C = Instance("test", ROOT, {}) addFields(C, {"inst": C}) @@ -90,14 +90,14 @@ assert c.inst == null(C) def test_simple_super(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) D = Instance("test2", C, {}) d = new(D) assert d.a == 3 def test_simple_field_shadowing(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) py.test.raises(TypeError, """D = Instance("test2", C, {"a": (Signed, 3)})""") @@ -131,7 +131,7 @@ return self.a + b m = meth(M, _name="m", _callable=m_) - C = Instance("test", None, {"a": (Signed, 2)}, {"m": m}) + C = Instance("test", ROOT, {"a": (Signed, 2)}, {"m": m}) c = new(C) assert c.m(3) == 5 @@ -146,12 +146,12 @@ return self.a + b m = meth(M, _name="m", _callable=m_) - py.test.raises(TypeError, """Instance("test", None, {"a": M})""") + py.test.raises(TypeError, """Instance("test", ROOT, {"a": M})""") - py.test.raises(TypeError, """Instance("test", None, {"m": Signed}, {"m":m})""") + py.test.raises(TypeError, """Instance("test", ROOT, {"m": Signed}, {"m":m})""") def test_simple_recursive_meth(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) M = Meth([C], Signed) def m_(self, other): @@ -164,7 +164,7 @@ assert c.m(c) == 6 def test_explicit_name_clash(): - C = Instance("test", None, {}) + C = Instance("test", ROOT, {}) addFields(C, {"a": (Signed, 3)}) @@ -178,7 +178,7 @@ py.test.raises(TypeError, """addFields(C, {"b": Signed})""") def test_instanceof(): - C = Instance("test", None, {}) + C = Instance("test", ROOT, {}) D = Instance("test2", C, {}) c = new(C) d = new(D) @@ -188,7 +188,7 @@ assert instanceof(d, C) def test_superclass_meth_lookup(): - C = Instance("test", None, {"a": (Signed, 3)}) + C = Instance("test", ROOT, {"a": (Signed, 3)}) M = Meth([C], Signed) def m_(self, other): @@ -211,7 +211,7 @@ assert d.m(d) == 9 def test_isSubclass(): - A = Instance("A", None) + A = Instance("A", ROOT) B = Instance("B", A) C = Instance("C", A) D = Instance("D", C) @@ -226,11 +226,11 @@ assert not isSubclass(D, B) def test_commonBaseclass(): - A = Instance("A", None) + A = Instance("A", ROOT) B = Instance("B", A) C = Instance("C", A) D = Instance("D", C) - E = Instance("E", None) + E = Instance("E", ROOT) F = Instance("F", E) assert commonBaseclass(A, A) == A @@ -247,12 +247,12 @@ assert commonBaseclass(B, D) == A assert commonBaseclass(C, D) == C - assert commonBaseclass(E, A) is None - assert commonBaseclass(E, B) is None - assert commonBaseclass(F, A) is None + assert commonBaseclass(E, A) is ROOT + assert commonBaseclass(E, B) is ROOT + assert commonBaseclass(F, A) is ROOT def test_equality(): - A = Instance("A", None) + A = Instance("A", ROOT) B = Instance("B", A) a1 = new(A) a2 = new(A) @@ -278,7 +278,7 @@ ] def test_subclassof(): - A = Instance("A", None) + A = Instance("A", ROOT) B = Instance("B", A) C = Instance("C", B) result = [] Modified: pypy/branch/njriley-trans/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rbuiltin.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rbuiltin.py Fri Mar 10 06:12:02 2006 @@ -11,6 +11,7 @@ from pypy.rpython.robject import pyobj_repr from pypy.rpython.rdict import rtype_r_dict from pypy.tool import sourcetools +from pypy.rpython import extregistry class __extend__(annmodel.SomeBuiltin): def rtyper_makerepr(self, rtyper): @@ -30,7 +31,13 @@ def rtyper_makekey(self): if self.s_self is None: # built-in function case - return self.__class__, getattr(self, 'const', None) + + const = getattr(self, 'const', None) + + if extregistry.is_registered(const): + const = extregistry.lookup(const) + + return self.__class__, const else: # built-in method case # NOTE: we hash by id of self.s_self here. This appears to be @@ -53,14 +60,17 @@ def rtype_simple_call(self, hop): try: bltintyper = BUILTIN_TYPER[self.builtinfunc] - except KeyError: + except (KeyError, TypeError): try: rtyper = hop.rtyper bltintyper = rtyper.type_system.rbuiltin.\ BUILTIN_TYPER[self.builtinfunc] - except KeyError: + except (KeyError, TypeError): if hasattr(self.builtinfunc,"specialize"): bltintyper = self.builtinfunc.specialize + elif extregistry.is_registered(self.builtinfunc): + entry = extregistry.lookup(self.builtinfunc) + bltintyper = entry.specialize_call else: raise TyperError("don't know about built-in function %r" % ( self.builtinfunc,)) Modified: pypy/branch/njriley-trans/pypy/rpython/rclass.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rclass.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rclass.py Fri Mar 10 06:12:02 2006 @@ -71,7 +71,7 @@ if self.classdef.commonbase(subclassdef) != self.classdef: raise TyperError("not a subclass of %r: %r" % ( self.classdef.name, desc)) - # + return getclassrepr(self.rtyper, subclassdef).getruntime() def convert_const(self, value): @@ -135,6 +135,35 @@ def new_instance(self, llops): pass + def convert_const(self, value): + if value is None: + return self.null_instance() + if isinstance(value, types.MethodType): + value = value.im_self # bound method -> instance + bk = self.rtyper.annotator.bookkeeper + try: + classdef = bk.getuniqueclassdef(value.__class__) + except KeyError: + raise TyperError("no classdef: %r" % (value.__class__,)) + if classdef != self.classdef: + # if the class does not match exactly, check that 'value' is an + # instance of a subclass and delegate to that InstanceRepr + if classdef.commonbase(self.classdef) != self.classdef: + raise TyperError("not an instance of %r: %r" % ( + self.classdef.name, value)) + rinstance = getinstancerepr(self.rtyper, classdef) + result = rinstance.convert_const(value) + return self.upcast(result) + # common case + try: + return self.prebuiltinstances[id(value)][1] + except KeyError: + self.setup() + result = self.create_instance() + self.prebuiltinstances[id(value)] = value, result + self.initialize_prebuilt_instance(value, classdef, result) + return result + def rtype_type(self, hop): pass Modified: pypy/branch/njriley-trans/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rctypes/implementation.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rctypes/implementation.py Fri Mar 10 06:12:02 2006 @@ -9,33 +9,38 @@ if sys.platform == "win32": from ctypes import _FUNCFLAG_STDCALL from pypy.annotation.model import SomeInteger, SomeCTypesObject, \ - SomeString, SomeFloat + SomeString, SomeFloat, SomeBuiltin from pypy.rpython.lltypesystem.lltype import Signed, SignedLongLong, \ Unsigned, UnsignedLongLong, Char, Float, Ptr, \ GcStruct, Struct, \ Void from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst from pypy.rpython.error import TyperError +from pypy.rpython import extregistry from pypy.annotation.pairtype import pairtype +from pypy.rpython import rint +# Importing for side effect of registering types with extregistry +import pypy.rpython.rctypes.rarray +import pypy.rpython.rctypes.rprimitive # ctypes_annotation_list contains various attributes that # are used by the pypy annotation. ctypes_annotation_list = [ - (c_char, Char, None), - (c_byte, Signed, None), - (c_ubyte, Unsigned, None), - (c_short, Signed, None), - (c_ushort, Unsigned, None), - (c_int, Signed, None), - (c_uint, Unsigned, None), - (c_long, Signed, None), - (c_ulong, Unsigned, None), - (c_longlong, SignedLongLong, None), - (c_ulonglong, UnsignedLongLong, None), - (c_float, Float, None), - (c_double, Float, None), +# (c_char, Char, None), +# (c_byte, Signed, None), +# (c_ubyte, Unsigned, None), +# (c_short, Signed, None), +# (c_ushort, Unsigned, None), +# (c_int, Signed, None), +# (c_uint, Unsigned, None), +# (c_long, Signed, None), +# (c_ulong, Unsigned, None), +# (c_longlong, SignedLongLong, None), +# (c_ulonglong, UnsignedLongLong, None), +# (c_float, Float, None), +# (c_double, Float, None), (c_char_p, None, staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), (POINTER(c_char), None, @@ -63,11 +68,74 @@ # the basic c_types need some annotation information # at the moment that are exactly the types that have # no 'wrap_arg'. This might change in the future - the_type.compute_result_annotation = classmethod(lambda cls, s_arg:SomeCTypesObject(cls)) + #the_type.compute_result_annotation = classmethod(lambda cls, s_arg:SomeCTypesObject(cls)) + def do_register(the_type): + extregistry.register_value(the_type, + compute_result_annotation=lambda s_arg: SomeCTypesObject(the_type)) + # XXX we need to register the correct repr for each primitive + extregistry.register_type(the_type, + get_repr=lambda rtyper, s_primitive: rint.signed_repr) + do_register(the_type) the_type.default_memorystate = SomeCTypesObject.NOMEMORY create_ctypes_annotations() +CFuncPtrType = type(ctypes.CFUNCTYPE(None)) + +def cfuncptrtype_compute_annotation(type, instance): + def compute_result_annotation(*args_s): + """ + Answer the annotation of the external function's result + """ + # Take 3, Check whether we can get away with the cheap + # precomputed solution and if not it, use a special + # attribute with the memory state + try: + return instance.restype.annotator_type + except AttributeError: + return SomeCTypesObject( + instance.restype, + instance.restype.external_function_result_memorystate ) + # Take 2, looks like we need another level of indirection + # That's to complicated + #o#return self.restype.compute_external_function_result_annotator_type() + # TODO: Check whether the function returns a pointer + # an correct the memory state appropriately + try: + return instance.restype.annotator_type + except AttributeError: + return SomeCTypesObject(instance.restype) + + return SomeBuiltin(compute_result_annotation, + methodname=instance.__name__) + +def cfuncptrtype_specialize_call(hop): + # this is necessary to get the original function pointer when specializing + # the metatype + cfuncptr = hop.spaceop.args[0].value + + def convert_params(backend, param_info_list): + assert "c" == backend.lower() + assert cfuncptr.argtypes is not None + answer = [] + for ctype_type, (ll_type, arg_name) in zip(cfuncptr.argtypes, + param_info_list): + if ll_type == ctype_type.ll_type: + answer.append(arg_name) + else: + answer.append(ctype_type.wrap_arg(ll_type, arg_name)) + return answer + + return hop.llops.gencapicall( + cfuncptr.__name__, + hop.args_v, + resulttype = cfuncptr.restype.ll_type, + _callable=None, + convert_params = convert_params ) + +extregistry.register_metatype(CFuncPtrType, + compute_annotation=cfuncptrtype_compute_annotation, + specialize_call=cfuncptrtype_specialize_call) class FunctionPointerTranslation(object): @@ -98,9 +166,12 @@ return id(self) def specialize(self, hop): - return hop.llops.gencapicall(self.__name__, hop.args_v, - resulttype=self.restype.ll_type, _callable=None, - convert_params=self.convert_params) + return hop.llops.gencapicall( + self.__name__, + hop.args_v, + resulttype = self.restype.ll_type, + _callable=None, + convert_params = self.convert_params ) def convert_params(self, backend, param_info_list): assert "c" == backend.lower() @@ -123,11 +194,15 @@ def __new__(mta,name,bases,clsdict): _fields = clsdict.get('_fields_',None) _adict = {} + ll_types = [] if _fields is not None: for attr, atype in _fields: _adict[attr] = atype + ll_types.append( ( attr, atype.ll_type ) ) clsdict['_fields_def_'] = _adict - print "_fields_def_ s:", _adict + # ll_type is just the C-level data part of the structure + clsdict[ "ll_type" ] = Struct( "C-Data_%s" % name, *ll_types ) + #d#print "_fields_def_ s:", _adict return super(RStructureMeta,mta).__new__(mta, name, bases, clsdict) @@ -221,7 +296,12 @@ """ Create a lowlevel representation for the pointer. """ - return CtypesMemoryOwningPointerRepresentation( rtyper, annotationObject ) + if annotationObject.memorystate == annotationObject.OWNSMEMORY: + return CtypesMemoryOwningPointerRepresentation( rtyper, annotationObject ) + elif annotationObject.memorystate == annotationObject.MEMORYALIAS: + return CtypesMemoryAliasPointerRepresentation( rtyper, annotationObject ) + else: + raise TyperError( "Unkown memory state in %r" % annotationObject ) answer.createLowLevelRepresentation = staticmethod( createLowLevelRepresentation ) @@ -248,60 +328,69 @@ # because we can't use the memory state from 'cls'. # So the obvious way to do it is obsolete (#o#). answer._fields_def_ = {"contents": cls} - print "p _fields_def_:", answer._fields_def_ + #d#print "p _fields_def_:", answer._fields_def_ # XXX Think about that twice and think about obsoleting # the obsoletion above answer.default_memorystate = None answer.external_function_result_memorystate = SomeCTypesObject.MEMORYALIAS + + # Add a low level type attribute, which is only used for computing the + # result of an external function. In other words this is just the non + # gc case + try: + answer.ll_type = Ptr( + Struct( + 'CtypesMemoryAliasPointer_%s' % answer.__name__, + ( "contents", answer._type_.ll_type ) ) ) + except TypeError: + pass return answer -class RCDLL(CDLL): - """ - This is the restricted version of ctypes' CDLL class. - """ - - class _CdeclFuncPtr(FunctionPointerTranslation, CDLL._CdeclFuncPtr): - """ - A simple extension of ctypes function pointers that - implements a simple interface to the anotator. - """ - _flags_ = _FUNCFLAG_CDECL - - - -if sys.platform == "win32": - class RWinDLL(WinDLL): - """ - This is the restricted version of ctypes' WINDLL class - """ - - class _StdcallFuncPtr(FunctionPointerTranslation, WinDLL._StdcallFuncPtr): - """ - A simple extension of ctypes function pointers that - implements a simple interface to the anotator. - """ - _flags_ = _FUNCFLAG_STDCALL - -def RARRAY(typ,length): - answer = ARRAY(typ,length) - def compute_result_annotation(cls, *arg_s): - """ - Answer the result annotation of calling 'cls'. - """ - assert answer is cls - return SomeCTypesObject(cls, SomeCTypesObject.OWNSMEMORY) - answer.compute_result_annotation = classmethod(compute_result_annotation) - return answer - +# class RCDLL(CDLL): +# """ +# This is the restricted version of ctypes' CDLL class. +# """ +# +# class _CdeclFuncPtr(FunctionPointerTranslation, CDLL._CdeclFuncPtr): +# """ +# A simple extension of ctypes function pointers that +# implements a simple interface to the anotator. +# """ +# _flags_ = _FUNCFLAG_CDECL +# +# +# +# if sys.platform == "win32": +# class RWinDLL(WinDLL): +# """ +# This is the restricted version of ctypes' WINDLL class +# """ +# +# class _StdcallFuncPtr(FunctionPointerTranslation, WinDLL._StdcallFuncPtr): +# """ +# A simple extension of ctypes function pointers that +# implements a simple interface to the anotator. +# """ +# _flags_ = _FUNCFLAG_STDCALL + +# def RARRAY(typ,length): +# answer = ARRAY(typ,length) +# def compute_result_annotation(cls, *arg_s): +# """ +# Answer the result annotation of calling 'cls'. +# """ +# assert answer is cls +# return SomeCTypesObject(cls, SomeCTypesObject.OWNSMEMORY) +# answer.compute_result_annotation = classmethod(compute_result_annotation) +# return answer class AbstractCtypesRepresentation( Repr ): """ The abstract base class of all ctypes low level representations. """ - class AbstractCtypesStructureRepresentation( AbstractCtypesRepresentation ): """ The abstract base class of ctypes structures' low level representation. @@ -352,7 +441,8 @@ fields = [ ( name, ctypesType.ll_type ) for name, ctypesType in annotationObject.knowntype._fields_ ] name = annotationObject.knowntype.__name__ - self.c_data_lowleveltype = Struct( "C-Data_%s" % name, *fields ) + #o#self.c_data_lowleveltype = Struct( "C-Data_%s" % name, *fields ) + self.c_data_lowleveltype = annotationObject.knowntype.ll_type self.lowleveltype = Ptr( GcStruct( "CtypesStructure_%s" % name, @@ -382,10 +472,11 @@ def __init__( self, rtyper, annotationObject ): self.lowleveltype = Ptr( GcStruct( - 'CtypesPointer_%s' % annotationObject.knowntype.__name__, + 'CtypesMemoryOwningPointer_%s' % annotationObject.knowntype.__name__, ( "contents", rtyper.getrepr( - annotationObject.knowntype._type_.compute_annotation() ).lowleveltype ) ) ) + annotationObject.knowntype._type_.compute_annotation() + ).lowleveltype ) ) ) def rtype_getattr( self, highLevelOperation ): inputargs = [ @@ -401,9 +492,15 @@ to memory owned by an external library. """ + def __init__( self, rtyper, annotationObject ): + self.lowleveltype = annotationObject.knowntype.ll_type + class __extend__( SomeCTypesObject ): def rtyper_makerepr( self, rtyper ): + if extregistry.is_registered_type(self.knowntype): + entry = extregistry.lookup_type(self.knowntype) + return entry.get_repr(rtyper, self) return self.knowntype.createLowLevelRepresentation( rtyper, self ) def rtyper_makekey( self ): Modified: pypy/branch/njriley-trans/pypy/rpython/rctypes/interface.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rctypes/interface.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rctypes/interface.py Fri Mar 10 06:12:02 2006 @@ -1,18 +1,18 @@ -from ctypes import _DLLS -from implementation import RCDLL as CDLL, c_int, c_char_p, \ +from ctypes import cdll +from implementation import c_int, c_char_p, \ c_char, c_byte, c_ubyte, \ c_short, c_ushort, c_uint,\ c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ RStructure as Structure, RByref as byref, RPOINTER as POINTER, \ - RARRAY as ARRAY -try: - from implementation import RWinDLL as WinDLL -except ImportError: - WinDLL = None - -cdll = _DLLS(CDLL) -if WinDLL: - windll = _DLLS(WinDLL) + ARRAY +#try: +# from implementation import RWinDLL as WinDLL +#except ImportError: +# WinDLL = None + +#cdll = _DLLS(CDLL) +#if WinDLL: +# windll = _DLLS(WinDLL) """ Modified: pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rctypes/test/test_rctypes.py Fri Mar 10 06:12:02 2006 @@ -11,6 +11,7 @@ from pypy.annotation.model import SomeCTypesObject, SomeObject from pypy import conftest import sys +from pypy.rpython.test.test_llinterp import interpret thisdir = py.magic.autopath().dirpath() @@ -42,15 +43,25 @@ py.test.skip("this test needs ctypes installed") +py.test.skip("these tests are broken while the ctypes primitive types are ported to use the extregistry") + from pypy.rpython.rctypes import cdll, c_char_p, c_int, c_char, \ c_char, c_byte, c_ubyte, c_short, c_ushort, c_uint,\ c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ POINTER, Structure, byref, ARRAY +# LoadLibrary is deprecated in ctypes, this should be removed at some point +if "load" in dir(cdll): + cdll_load = cdll.load +else: + cdll_load = cdll.LoadLibrary + if sys.platform == 'win32': - mylib = cdll.LoadLibrary('msvcrt.dll') + mylib = cdll_load('msvcrt.dll') elif sys.platform == 'linux2': - mylib = cdll.LoadLibrary('libc.so.6') + mylib = cdll_load('libc.so.6') +elif sys.platform == 'darwin': + mylib = cdll.c else: py.test.skip("don't know how to load the c lib for %s" % sys.platform) @@ -73,9 +84,9 @@ compile_c_module([thisdir.join("_rctypes_test.c")], "_rctypes_test") if sys.platform == "win32": - _rctypes_test = cdll.LoadLibrary("_rctypes_test.pyd") + _rctypes_test = cdll_load("_rctypes_test.pyd") else: - _rctypes_test = cdll.LoadLibrary(str(thisdir.join("_rctypes_test.so"))) + _rctypes_test = cdll_load(str(thisdir.join("_rctypes_test.so"))) # _testfunc_byval testfunc_byval = _rctypes_test._testfunc_byval @@ -234,7 +245,6 @@ s.y = y return s - class Test_rctypes: def test_simple(self): @@ -265,16 +275,19 @@ class Test_structure: def test_simple_as_extension_module(self): - import _rctypes_test as t0 - import _rctypes_test as t1 + # Full path names follow because of strange behavior in the presence + # of an __init__.py in this test directory. When there is an + # __init__.py then the full path names appear in sys.modules + import pypy.rpython.rctypes.test._rctypes_test as t0 + import pypy.rpython.rctypes.test._rctypes_test as t1 assert t1 is t0 - assert "_rctypes_test" in sys.modules + assert "pypy.rpython.rctypes.test._rctypes_test" in sys.modules def test_simple(self): if sys.platform == "win32": - dll = cdll.LoadLibrary("_rctypes_test.pyd") + dll = cdll_load("_rctypes_test.pyd") else: - dll = cdll.LoadLibrary(str(thisdir.join("_rctypes_test.so"))) + dll = cdll_load(str(thisdir.join("_rctypes_test.so"))) in_point = tagpoint() in_point.x = 42 in_point.y = 17 @@ -292,10 +305,13 @@ def test_annotate_struct(self): a = RPythonAnnotator() - s = a.build_types(py_testfunc_struct, [int]) + s = a.build_types(py_testfunc_struct, [tagpoint]) assert s.knowntype == int + + if conftest.option.view: + a.translator.view() - def test_annotate_struct(self): + def test_annotate_struct2(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_struct_id, [tagpoint]) @@ -316,6 +332,9 @@ s = a.build_types(py_create_point,[]) assert s.knowntype == int + if conftest.option.view: + a.translator.view() + def test_annotate_byval(self): t = TranslationContext() a = t.buildannotator() @@ -357,7 +376,7 @@ #d#t.view() assert s.knowntype == tagpoint # This memory state will be supported in the future (#f#) - # Obviously the test is wrong for now + # Obviously the test is wrong for now #f#assert s.memorystate == SomeCTypesObject.MIXEDMEMORYOWNERSHIP assert isinstance(s, SomeObject) @@ -399,8 +418,8 @@ try: t.buildrtyper().specialize() finally: - #d#t.view() - pass + if conftest.option.view: + t.view() def test_specialize_struct_1(self): t = TranslationContext() @@ -413,14 +432,14 @@ #d#t.view() pass - # This does not work yet, ctype structures and pointers are - # missing the ll_type attribute that directly maps ctypes objects - # to the lltype system - # TODO: Find an indirect way to get that mapping done - def x_test_specialize_pointer_to_struct(self): + def test_specialize_pointer_to_struct(self): t = self.test_annotate_pointer_to_struct() t.buildrtyper().specialize() - t.view() + if conftest.option.view: + t.view() + + def x_test_compile_pointer_to_struct(self): + fn = compile( py_testfunc_struct_pointer_id, [ oppoint_type ] ) def test_compile_struct(self): fn = compile( py_test_compile_struct, [ int, int ] ) @@ -451,62 +470,3 @@ fn = compile( py_test_compile_pointer, [ int, int ] ) res = fn( -42, 42 ) assert res == -42 - - -class Test_array: - - def test_annotate_array(self): - a = RPythonAnnotator() - s = a.build_types(py_test_annotate_array, []) - assert s.knowntype == c_int_10 - - def test_annotate_array_access(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_content, []) - assert s.knowntype == int - #d#t.view() - - def test_annotate_pointer_access_as_array(self): - """ - Make sure that pointers work the same way as arrays, for - ctypes compatibility. - - :Note: This works because pointer and array classes both - have a _type_ attribute, that contains the type of the - object pointed to or in the case of an array the element type. - """ - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_pointer_content, []) - assert s.knowntype == int - #d#t.view() - - def test_annotate_array_slice_access(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_slice_content, []) - #d#t.view() - #d#print "v90:", s, type(s) - assert s.knowntype == list - s.listdef.listitem.s_value.knowntype == int - - def test_annotate_array_access_variable(self): - t = TranslationContext() - a = t.buildannotator() - s = a.build_types(py_test_annotate_array_content_variable_index, []) - assert s.knowntype == int - #t#t.view() - - def test_annotate_array_access_index_error_on_positive_index(self): - t = TranslationContext() - a = t.buildannotator() - - py.test.raises(IndexError, "s = a.build_types(py_test_annotate_array_content_index_error_on_positive_index,[])") - - def test_annotate_array_access_index_error_on_negative_index(self): - t = TranslationContext() - a = t.buildannotator() - - py.test.raises(IndexError, "s = a.build_types(py_test_annotate_array_content_index_error_on_negative_index,[])") - Modified: pypy/branch/njriley-trans/pypy/rpython/rgenop.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rgenop.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rgenop.py Fri Mar 10 06:12:02 2006 @@ -4,7 +4,7 @@ that can be used to produce any other kind of graph. """ -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.objspace.flow import model as flowmodel from pypy.translator.simplify import eliminate_empty_blocks, join_blocks from pypy.rpython.module.support import init_opaque_object @@ -72,6 +72,16 @@ assert not isinstance(llvalue, str) and not isinstance(llvalue, lltype.LowLevelType) return to_opaque_object(v) +def revealconst(T, gv_value): + c = from_opaque_object(gv_value) + assert isinstance(c, flowmodel.Constant) + if isinstance(T, lltype.Ptr): + return lltype.cast_pointer(T, c.value) + elif T == llmemory.Address: + return llmemory.cast_ptr_to_adr(c.value) + else: + return lltype.cast_primitive(T, c.value) + # XXX # temporary interface; it's unclera if genop itself should change to ease dinstinguishing # Void special args from the rest. Or there should be variation for the ops involving them @@ -238,6 +248,7 @@ setannotation(geninputarg, s_ConstOrVar) setannotation(genop, s_ConstOrVar) setannotation(genconst, s_ConstOrVar) +revealconst.compute_result_annotation = lambda s_T, s_gv: annmodel.lltype_to_annotation(s_T.const) setannotation(closeblock1, s_Link) setannotation(closeblock2, s_LinkPair) setannotation(closelink, None) @@ -248,6 +259,7 @@ setspecialize(geninputarg) setspecialize(genop) setspecialize(genconst) +setspecialize(revealconst) setspecialize(closeblock1) setspecialize(closeblock2) setspecialize(closelink) Modified: pypy/branch/njriley-trans/pypy/rpython/rmodel.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rmodel.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rmodel.py Fri Mar 10 06:12:02 2006 @@ -4,7 +4,7 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem.lltype import \ Void, Bool, Float, Signed, Char, UniChar, \ - typeOf, LowLevelType, Ptr, PyObject + typeOf, LowLevelType, Ptr, PyObject, isCompatibleType from pypy.rpython.ootypesystem import ootype from pypy.rpython.error import TyperError, MissingRTypeOperation @@ -235,22 +235,7 @@ def rtype_is_((robj1, robj2), hop): if hop.s_result.is_constant(): return inputconst(Bool, hop.s_result.const) - roriginal1 = robj1 - roriginal2 = robj2 - if robj1.lowleveltype is Void: - robj1 = robj2 - elif robj2.lowleveltype is Void: - robj2 = robj1 - if (not isinstance(robj1.lowleveltype, Ptr) or - not isinstance(robj2.lowleveltype, Ptr)): - raise TyperError('is of instances of the non-pointers: %r, %r' % ( - roriginal1, roriginal2)) - if robj1.lowleveltype != robj2.lowleveltype: - raise TyperError('is of instances of different pointer types: %r, %r' % ( - roriginal1, roriginal2)) - - v_list = hop.inputargs(robj1, robj2) - return hop.genop('ptr_eq', v_list, resulttype=Bool) + return hop.rtyper.type_system.generic_is(robj1, robj2, hop) # ____________________________________________________________ @@ -344,7 +329,7 @@ realtype = typeOf(value) except (AssertionError, AttributeError): realtype = '???' - if realtype != lltype: + if not isCompatibleType(realtype, lltype): raise TyperError("inputconst(reqtype = %s, value = %s):\n" "expected a %r,\n" " got a %r" % (reqtype, value, Modified: pypy/branch/njriley-trans/pypy/rpython/rpbc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rpbc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rpbc.py Fri Mar 10 06:12:02 2006 @@ -7,7 +7,8 @@ from pypy.rpython.lltypesystem.lltype import \ typeOf, Void, Bool, nullptr, frozendict, Ptr, Struct, malloc from pypy.rpython.error import TyperError -from pypy.rpython.rmodel import Repr, inputconst, HalfConcreteWrapper, CanBeNull +from pypy.rpython.rmodel import Repr, inputconst, HalfConcreteWrapper, CanBeNull, \ + mangle, inputdesc, warning from pypy.rpython import rclass from pypy.rpython import robject @@ -25,7 +26,7 @@ if sample.overridden: getRepr = OverriddenFunctionPBCRepr else: - getRepr = FunctionsPBCRepr + getRepr = rtyper.type_system.rpbc.FunctionsPBCRepr else: getRepr = getFrozenPBCRepr elif issubclass(kind, description.ClassDesc): @@ -154,7 +155,7 @@ return concretetable, uniquerows -class FunctionsPBCRepr(CanBeNull, Repr): +class AbstractFunctionsPBCRepr(CanBeNull, Repr): """Representation selected for a PBC of function(s).""" def __init__(self, rtyper, s_pbc): @@ -176,10 +177,7 @@ # several functions, each with several specialized variants. # each function becomes a pointer to a Struct containing # pointers to its variants. - fields = [] - for row in uniquerows: - fields.append((row.attrname, row.fntype)) - self.lowleveltype = Ptr(Struct('specfunc', *fields)) + self.lowleveltype = self.setup_specfunc() self.funccache = {} def get_s_callable(self): @@ -229,7 +227,7 @@ result = llfn # from the loop above else: # build a Struct with all the values collected in 'llfns' - result = malloc(self.lowleveltype.TO, immortal=True) + result = self.create_specfunc() for attrname, llfn in llfns.items(): setattr(result, attrname, llfn) self.funccache[funcdesc] = result @@ -266,7 +264,7 @@ # 'v' is a Struct pointer, read the corresponding field row = self.concretetable[shape, index] cname = inputconst(Void, row.attrname) - return llop.genop('getfield', [v, cname], resulttype = row.fntype) + return self.get_specfunc_row(llop, v, cname, row.fntype) def get_unique_llfn(self): # try to build a unique low-level function. Avoid to use @@ -319,7 +317,7 @@ v = hop.genop('indirect_call', vlist, resulttype = rresult) return hop.llops.convertvar(v, rresult, hop.r_result) -class __extend__(pairtype(FunctionsPBCRepr, FunctionsPBCRepr)): +class __extend__(pairtype(AbstractFunctionsPBCRepr, AbstractFunctionsPBCRepr)): def convert_from_to((r_fpbc1, r_fpbc2), v, llops): # this check makes sense because both source and dest repr are FunctionsPBCRepr if r_fpbc1.lowleveltype == r_fpbc2.lowleveltype: @@ -378,6 +376,146 @@ assert frozendesc is self.frozendesc return object() # lowleveltype is Void + +class AbstractMultipleFrozenPBCRepr(CanBeNull, Repr): + + def _setup_repr_fields(self): + fields = [] + self.fieldmap = {} + if self.access_set is not None: + attrlist = self.access_set.attrs.keys() + attrlist.sort() + for attr in attrlist: + s_value = self.access_set.attrs[attr] + r_value = self.rtyper.getrepr(s_value) + mangled_name = mangle('pbc', attr) + fields.append((mangled_name, r_value.lowleveltype)) + self.fieldmap[attr] = mangled_name, r_value + return fields + + def convert_desc(self, frozendesc): + if (self.access_set is not None and + frozendesc not in self.access_set.descs): + raise TyperError("not found in PBC access set: %r" % (frozendesc,)) + try: + return self.pbc_cache[frozendesc] + except KeyError: + self.setup() + result = self.create_instance() + self.pbc_cache[frozendesc] = result + for attr, (mangled_name, r_value) in self.fieldmap.items(): + if r_value.lowleveltype is Void: + continue + try: + thisattrvalue = frozendesc.read_attribute(attr) + except AttributeError: + warning("Desc %r has no attribute %r" % (frozendesc, attr)) + continue + llvalue = r_value.convert_const(thisattrvalue) + setattr(result, mangled_name, llvalue) + return result + + def convert_const(self, pbc): + if pbc is None: + return self.null_instance() + if isinstance(pbc, types.MethodType) and pbc.im_self is None: + value = pbc.im_func # unbound method -> bare function + frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc) + return self.convert_desc(frozendesc) + + def rtype_getattr(self, hop): + attr = hop.args_s[1].const + vpbc, vattr = hop.inputargs(self, Void) + v_res = self.getfield(vpbc, attr, hop.llops) + mangled_name, r_res = self.fieldmap[attr] + return hop.llops.convertvar(v_res, r_res, hop.r_result) + +class __extend__(pairtype(AbstractMultipleFrozenPBCRepr, AbstractMultipleFrozenPBCRepr)): + def convert_from_to((r_pbc1, r_pbc2), v, llops): + if r_pbc1.access_set == r_pbc2.access_set: + return v + return NotImplemented + +class __extend__(pairtype(SingleFrozenPBCRepr, AbstractMultipleFrozenPBCRepr)): + def convert_from_to((r_pbc1, r_pbc2), v, llops): + frozendesc1 = r_pbc1.frozendesc + access = frozendesc1.queryattrfamily() + if access is r_pbc2.access_set: + return inputdesc(r_pbc2, frozendesc1) + return NotImplemented + + +class MethodOfFrozenPBCRepr(Repr): + """Representation selected for a PBC of method object(s) of frozen PBCs. + It assumes that all methods are the same function bound to different PBCs. + The low-level representation can then be a pointer to that PBC.""" + + def __init__(self, rtyper, s_pbc): + self.rtyper = rtyper + self.funcdesc = s_pbc.descriptions.keys()[0].funcdesc + + # a hack to force the underlying function to show up in call_families + # (generally not needed, as normalizecalls() should ensure this, + # but needed for bound methods that are ll helpers) + # XXX sort this out + #call_families = rtyper.annotator.getpbccallfamilies() + #call_families.find((None, self.function)) + + if s_pbc.can_be_none(): + raise TyperError("unsupported: variable of type " + "method-of-frozen-PBC or None") + + im_selves = [] + for desc in s_pbc.descriptions: + assert desc.funcdesc is self.funcdesc + im_selves.append(desc.frozendesc) + + self.s_im_self = annmodel.SomePBC(im_selves) + self.r_im_self = rtyper.getrepr(self.s_im_self) + self.lowleveltype = self.r_im_self.lowleveltype + + def get_s_callable(self): + return annmodel.SomePBC([self.funcdesc]) + + def get_r_implfunc(self): + r_func = self.rtyper.getrepr(self.get_s_callable()) + return r_func, 1 + + def convert_desc(self, mdesc): + if mdesc.funcdesc is not self.funcdesc: + raise TyperError("not a method bound on %r: %r" % (self.funcdesc, + mdesc)) + return self.r_im_self.convert_desc(mdesc.frozendesc) + + def convert_const(self, method): + mdesc = self.rtyper.annotator.bookkeeper.getdesc(method) + return self.convert_desc(mdesc) + + def rtype_simple_call(self, hop): + return self.redispatch_call(hop, call_args=False) + + def rtype_call_args(self, hop): + return self.redispatch_call(hop, call_args=True) + + def redispatch_call(self, hop, call_args): + # XXX obscure, try to refactor... + s_function = annmodel.SomePBC([self.funcdesc]) + hop2 = hop.copy() + hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self' + hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self') + if isinstance(hop2.args_v[0], Constant): + boundmethod = hop2.args_v[0].value + hop2.args_v[0] = Constant(boundmethod.im_self) + if call_args: + hop2.swap_fst_snd_args() + _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape + adjust_shape(hop2, s_shape) + # a marker that would crash if actually used... + c = Constant("obscure-don't-use-me") + hop2.v_s_insertfirstarg(c, s_function) # insert 'function' + # now hop2 looks like simple_call(function, self, args...) + return hop2.dispatch() + # __ None ____________________________________________________ class NoneFrozenPBCRepr(SingleFrozenPBCRepr): @@ -468,6 +606,18 @@ r_res = self.rtyper.getrepr(s_res) return hop.llops.convertvar(v_res, r_res, hop.r_result) + def replace_class_with_inst_arg(self, hop, v_inst, s_inst, call_args): + hop2 = hop.copy() + hop2.r_s_popfirstarg() # discard the class pointer argument + if call_args: + _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape + hop2.v_s_insertfirstarg(v_inst, s_inst) # add 'instance' + adjust_shape(hop2, s_shape) + else: + hop2.v_s_insertfirstarg(v_inst, s_inst) # add 'instance' + return hop2 + + class __extend__(pairtype(AbstractClassesPBCRepr, rclass.AbstractClassRepr)): def convert_from_to((r_clspbc, r_cls), v, llops): # turn a PBC of classes to a standard pointer-to-vtable class repr @@ -481,7 +631,7 @@ r_clspbc.rtyper.type_system.rclass.CLASSTYPE) if not r_clspbc.get_class_repr().classdef.issubclass(r_cls.classdef): return NotImplemented - return r_cls.fromtypeptr(v, llops) + return r_cls.fromclasstype(v, llops) class __extend__(pairtype(AbstractClassesPBCRepr, AbstractClassesPBCRepr)): def convert_from_to((r_clspbc1, r_clspbc2), v, llops): @@ -492,6 +642,12 @@ return inputconst(r_clspbc2, r_clspbc1.s_pbc.const) return NotImplemented +def adjust_shape(hop2, s_shape): + new_shape = (s_shape.const[0]+1,) + s_shape.const[1:] + c_shape = Constant(new_shape) + s_shape = hop2.rtyper.annotator.bookkeeper.immutablevalue(new_shape) + hop2.v_s_insertfirstarg(c_shape, s_shape) # reinsert adjusted shape + class AbstractMethodsPBCRepr(Repr): """Representation selected for a PBC of MethodDescs. It assumes that all the methods come from the same name and have @@ -541,6 +697,16 @@ # (as shown for example in test_rclass/test_method_both_A_and_B) return llops.convertvar(v_inst, r_inst, self.r_im_self) + def add_instance_arg_to_hop(self, hop, call_args): + hop2 = hop.copy() + hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self' + hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self') + + if call_args: + hop2.swap_fst_snd_args() + _, s_shape = hop2.r_s_popfirstarg() + adjust_shape(hop2, s_shape) + return hop2 # ____________________________________________________________ ##def getsignature(rtyper, func): Modified: pypy/branch/njriley-trans/pypy/rpython/rtyper.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/rtyper.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/rtyper.py Fri Mar 10 06:12:02 2006 @@ -66,10 +66,8 @@ for s_primitive, lltype in annmodel.annotation_to_ll_map: r = self.getrepr(s_primitive) self.primitive_to_repr[r.lowleveltype] = r - if type_system == "lltype": - from pypy.rpython.lltypesystem.exceptiondata import ExceptionData - - self.exceptiondata = ExceptionData(self) + if self.type_system.offers_exceptiondata: + self.exceptiondata = self.type_system.exceptiondata.ExceptionData(self) else: self.exceptiondata = None Modified: pypy/branch/njriley-trans/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/test/test_llinterp.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/test/test_llinterp.py Fri Mar 10 06:12:02 2006 @@ -65,6 +65,10 @@ _lastinterpreted = [] _tcache = {} +def clear_tcache(): + del _lastinterpreted[:] + _tcache.clear() + def get_interpreter(func, values, view='auto', viewbefore='auto', policy=None, someobjects=False, type_system="lltype"): key = (func,) + tuple([typeOf(x) for x in values])+ (someobjects,) @@ -423,6 +427,58 @@ fgraph.startblock.operations[0].opname = "flavored_malloc" fgraph.startblock.operations[0].args.insert(0, inputconst(Void, "stack")) py.test.raises(AttributeError, "interp.eval_graph(graph, [])") + + +def test_cleanup_finally(): + interp, graph = get_interpreter(cleanup_f, [-1]) + clear_tcache() # because we hack the graph in place + operations = graph.startblock.operations + assert operations[0].opname == "direct_call" + assert operations[1].opname == "direct_call" + assert getattr(operations[0], 'cleanup', None) is None + assert getattr(operations[1], 'cleanup', None) is None + cleanup_finally = (operations.pop(1),) + cleanup_except = () + operations[0].cleanup = cleanup_finally, cleanup_except + + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 102 + # state.current == 2 + res = interp.eval_graph(graph, [1]) + assert res == 203 + # state.current == 3 + py.test.raises(LLException, "interp.eval_graph(graph, [-1])") + # state.current == 4 + res = interp.eval_graph(graph, [1]) + assert res == 405 + # state.current == 5 + +def test_cleanup_except(): + interp, graph = get_interpreter(cleanup_f, [-1]) + clear_tcache() # because we hack the graph in place + operations = graph.startblock.operations + assert operations[0].opname == "direct_call" + assert operations[1].opname == "direct_call" + assert getattr(operations[0], 'cleanup', None) is None + assert getattr(operations[1], 'cleanup', None) is None + cleanup_finally = () + cleanup_except = (operations.pop(1),) + operations[0].cleanup = cleanup_finally, cleanup_except + + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 101 + # state.current == 1 + res = interp.eval_graph(graph, [1]) + assert res == 101 + # state.current == 1 + py.test.raises(LLException, "interp.eval_graph(graph, [-1])") + # state.current == 2 + res = interp.eval_graph(graph, [1]) + assert res == 202 + # state.current == 2 + #__________________________________________________________________ # example functions for testing the LLInterpreter _snap = globals().copy() @@ -483,3 +539,19 @@ except ValueError: raise TypeError +# test for the 'cleanup' attribute of SpaceOperations +class CleanupState(object): + pass +cleanup_state = CleanupState() +cleanup_state.current = 1 +def cleanup_g(n): + cleanup_state.saved = cleanup_state.current + if n < 0: + raise ZeroDivisionError +def cleanup_h(): + cleanup_state.current += 1 +def cleanup_f(n): + cleanup_g(n) + cleanup_h() # the test hacks the graph to put this h() in the + # cleanup clause of the previous direct_call(g) + return cleanup_state.saved * 100 + cleanup_state.current Modified: pypy/branch/njriley-trans/pypy/rpython/test/test_ootype_llinterp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/test/test_ootype_llinterp.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/test/test_ootype_llinterp.py Fri Mar 10 06:12:02 2006 @@ -2,7 +2,7 @@ from pypy.rpython.test.test_llinterp import interpret def test_simple_field(): - C = Instance("test", None, {'a': (Signed, 3)}) + C = Instance("test", ROOT, {'a': (Signed, 3)}) def f(): c = new(C) @@ -13,7 +13,7 @@ assert result == 5 def test_simple_method(): - C = Instance("test", None, {'a': (Signed, 3)}) + C = Instance("test", ROOT, {'a': (Signed, 3)}) M = Meth([], Signed) def m_(self): return self.a Modified: pypy/branch/njriley-trans/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/test/test_rclass.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/test/test_rclass.py Fri Mar 10 06:12:02 2006 @@ -1,79 +1,18 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.lltypesystem.lltype import * +from pypy.rpython.ootypesystem import ootype from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.rarithmetic import intmask + class EmptyBase(object): pass - -def test_simple(): - def dummyfn(): - x = EmptyBase() - return x - res = interpret(dummyfn, []) - T = typeOf(res) - assert isinstance(T, Ptr) and isinstance(T.TO, GcStruct) - -def test_instanceattr(): - def dummyfn(): - x = EmptyBase() - x.a = 5 - x.a += 1 - return x.a - res = interpret(dummyfn, []) - assert res == 6 - class Random: xyzzy = 12 yadda = 21 -def test_classattr(): - def dummyfn(): - x = Random() - return x.xyzzy - res = interpret(dummyfn, []) - assert res == 12 - -def test_classattr_as_defaults(): - def dummyfn(): - x = Random() - x.xyzzy += 1 - return x.xyzzy - res = interpret(dummyfn, []) - assert res == 13 - -def test_prebuilt_instance(): - a = EmptyBase() - a.x = 5 - def dummyfn(): - a.x += 1 - return a.x - interpret(dummyfn, []) - -def test_recursive_prebuilt_instance(): - a = EmptyBase() - b = EmptyBase() - a.x = 5 - b.x = 6 - a.peer = b - b.peer = a - def dummyfn(): - return a.peer.peer.peer.x - res = interpret(dummyfn, []) - assert res == 6 - -def test_prebuilt_instances_with_void(): - def marker(): - return 42 - a = EmptyBase() - a.nothing_special = marker - def dummyfn(): - return a.nothing_special() - res = interpret(dummyfn, []) - assert res == 42 - -# method calls +# for method calls class A: def f(self): return self.g() @@ -88,349 +27,503 @@ class C(B): pass -def test_simple_method_call(): - def f(i): - if i: - a = A() - else: - a = B() - return a.f() - res = interpret(f, [True]) - assert res == 42 - res = interpret(f, [False]) - assert res == 1 - -def test_isinstance(): - def f(i): - if i == 0: - o = None - elif i == 1: - o = A() - elif i == 2: - o = B() +class BaseTestRclass: + + def test_instanceattr(self): + def dummyfn(): + x = EmptyBase() + x.a = 5 + x.a += 1 + return x.a + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 6 + + def test_simple(self): + def dummyfn(): + x = EmptyBase() + return x + res = interpret(dummyfn, [], type_system=self.ts) + T = typeOf(res) + if self.ts == "lltype": + assert isinstance(T, Ptr) and isinstance(T.TO, GcStruct) else: - o = C() - return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C) + assert isinstance(T, ootype.Instance) - res = interpret(f, [1]) - assert res == 100 - res = interpret(f, [2]) - assert res == 110 - res = interpret(f, [3]) - assert res == 111 - - res = interpret(f, [0]) - assert res == 0 - -def test_method_used_in_subclasses_only(): - class A: - def meth(self): - return 123 - class B(A): - pass - def f(): - x = B() - return x.meth() - res = interpret(f, []) - assert res == 123 - -def test_method_both_A_and_B(): - class A: - def meth(self): - return 123 - class B(A): - pass - def f(): - a = A() - b = B() - return a.meth() + b.meth() - res = interpret(f, []) - assert res == 246 - -def test_issubclass_type(): - class Abstract: - pass - class A(Abstract): - pass - class B(A): - pass - def f(i): - if i == 0: - c1 = A() - else: - c1 = B() - return issubclass(type(c1), B) - assert interpret(f, [0], view=False, viewbefore=False) == False - assert interpret(f, [1], view=False, viewbefore=False) == True - - def g(i): - if i == 0: - c1 = A() - else: - c1 = B() - return issubclass(type(c1), A) - assert interpret(g, [0], view=False, viewbefore=False) == True - assert interpret(g, [1], view=False, viewbefore=False) == True - -def test_staticmethod(): - class A(object): - f = staticmethod(lambda x, y: x*y) - def f(): - a = A() - return a.f(6, 7) - res = interpret(f, []) - assert res == 42 - -def test_is(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() - c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) | - 0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) | - 0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) | - 0x0200*(d is e)) - res = interpret(f, [0]) - assert res == 0x0004 - res = interpret(f, [1]) - assert res == 0x0020 - res = interpret(f, [2]) - assert res == 0x0100 - res = interpret(f, [3]) - assert res == 0x0200 - -def test_eq(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() - c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a == b) | 0x0002*(a == c) | 0x0004*(a == d) | - 0x0008*(a == e) | 0x0010*(b == c) | 0x0020*(b == d) | - 0x0040*(b == e) | 0x0080*(c == d) | 0x0100*(c == e) | - 0x0200*(d == e)) - res = interpret(f, [0]) - assert res == 0x0004 - res = interpret(f, [1]) - assert res == 0x0020 - res = interpret(f, [2]) - assert res == 0x0100 - res = interpret(f, [3]) - assert res == 0x0200 - -def test_istrue(): - class A: - pass - def f(i): - if i == 0: + + def test_classattr(self): + def dummyfn(): + x = Random() + return x.xyzzy + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 12 + + def test_classattr_both(self): + print self.ts + class A: + a = 1 + class B(A): + a = 2 + def pick(i): + if i == 0: + return A + else: + return B + + def dummyfn(i): + C = pick(i) + i = C() + return C.a + i.a + res = interpret(dummyfn, [0], type_system=self.ts) + assert res == 2 + res = interpret(dummyfn, [1], type_system=self.ts) + assert res == 4 + + def test_classattr_as_defaults(self): + def dummyfn(): + x = Random() + x.xyzzy += 1 + return x.xyzzy + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 13 + + def test_prebuilt_instance(self): + a = EmptyBase() + a.x = 5 + def dummyfn(): + a.x += 1 + return a.x + interpret(dummyfn, [], type_system=self.ts) + + def test_recursive_prebuilt_instance(self): + a = EmptyBase() + b = EmptyBase() + a.x = 5 + b.x = 6 + a.peer = b + b.peer = a + def dummyfn(): + return a.peer.peer.peer.x + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 6 + + def test_prebuilt_instances_with_void(self): + def marker(): + return 42 + a = EmptyBase() + a.nothing_special = marker + def dummyfn(): + return a.nothing_special() + res = interpret(dummyfn, [], type_system=self.ts) + assert res == 42 + + def test_simple_method_call(self): + def f(i): + if i: + a = A() + else: + a = B() + return a.f() + res = interpret(f, [True], type_system=self.ts) + assert res == 42 + res = interpret(f, [False], type_system=self.ts) + assert res == 1 + + def test_isinstance(self): + def f(i): + if i == 0: + o = None + elif i == 1: + o = A() + elif i == 2: + o = B() + else: + o = C() + return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C) + + res = interpret(f, [1], type_system=self.ts) + assert res == 100 + res = interpret(f, [2], type_system=self.ts) + assert res == 110 + res = interpret(f, [3], type_system=self.ts) + assert res == 111 + + res = interpret(f, [0], type_system=self.ts) + assert res == 0 + + def test_method_used_in_subclasses_only(self): + class A: + def meth(self): + return 123 + class B(A): + pass + def f(): + x = B() + return x.meth() + res = interpret(f, [], type_system=self.ts) + assert res == 123 + + def test_method_both_A_and_B(self): + class A: + def meth(self): + return 123 + class B(A): + pass + def f(): a = A() - else: - a = None - if a: - return 1 - else: - return 2 - res = interpret(f, [0]) - assert res == 1 - res = interpret(f, [1]) - assert res == 2 - -def test_ne(): - class A: pass - class B(A): pass - class C: pass - def f(i): - a = A() - b = B() + b = B() + return a.meth() + b.meth() + res = interpret(f, [], type_system=self.ts) + assert res == 246 + + def test_issubclass_type(self): + class Abstract: + pass + class A(Abstract): + pass + class B(A): + pass + def f(i): + if i == 0: + c1 = A() + else: + c1 = B() + return issubclass(type(c1), B) + assert interpret(f, [0], type_system=self.ts) == False + assert interpret(f, [1], type_system=self.ts) == True + + def g(i): + if i == 0: + c1 = A() + else: + c1 = B() + return issubclass(type(c1), A) + assert interpret(g, [0], type_system=self.ts) == True + assert interpret(g, [1], type_system=self.ts) == True + + def test_staticmethod(self): + class A(object): + f = staticmethod(lambda x, y: x*y) + def f(): + a = A() + return a.f(6, 7) + res = interpret(f, [], type_system=self.ts) + assert res == 42 + + def test_is(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) | + 0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) | + 0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) | + 0x0200*(d is e)) + res = interpret(f, [0], type_system=self.ts) + assert res == 0x0004 + res = interpret(f, [1], type_system=self.ts) + assert res == 0x0020 + res = interpret(f, [2], type_system=self.ts) + assert res == 0x0100 + res = interpret(f, [3], type_system=self.ts) + assert res == 0x0200 + + def test_eq(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a == b) | 0x0002*(a == c) | 0x0004*(a == d) | + 0x0008*(a == e) | 0x0010*(b == c) | 0x0020*(b == d) | + 0x0040*(b == e) | 0x0080*(c == d) | 0x0100*(c == e) | + 0x0200*(d == e)) + res = interpret(f, [0], type_system=self.ts) + assert res == 0x0004 + res = interpret(f, [1], type_system=self.ts) + assert res == 0x0020 + res = interpret(f, [2], type_system=self.ts) + assert res == 0x0100 + res = interpret(f, [3]) + assert res == 0x0200 + + def test_istrue(self): + class A: + pass + def f(i): + if i == 0: + a = A() + else: + a = None + if a: + return 1 + else: + return 2 + res = interpret(f, [0], type_system=self.ts) + assert res == 1 + res = interpret(f, [1], type_system=self.ts) + assert res == 2 + + def test_ne(self): + class A: pass + class B(A): pass + class C: pass + def f(i): + a = A() + b = B() + c = C() + d = None + e = None + if i == 0: + d = a + elif i == 1: + d = b + elif i == 2: + e = c + return (0x0001*(a != b) | 0x0002*(a != c) | 0x0004*(a != d) | + 0x0008*(a != e) | 0x0010*(b != c) | 0x0020*(b != d) | + 0x0040*(b != e) | 0x0080*(c != d) | 0x0100*(c != e) | + 0x0200*(d != e)) + res = interpret(f, [0], type_system=self.ts) + assert res == ~0x0004 & 0x3ff + res = interpret(f, [1], type_system=self.ts) + assert res == ~0x0020 & 0x3ff + res = interpret(f, [2], type_system=self.ts) + assert res == ~0x0100 & 0x3ff + res = interpret(f, [3], type_system=self.ts) + assert res == ~0x0200 & 0x3ff + + def test_hash_preservation(self): + class C: + pass + class D(C): + pass c = C() - d = None - e = None - if i == 0: - d = a - elif i == 1: - d = b - elif i == 2: - e = c - return (0x0001*(a != b) | 0x0002*(a != c) | 0x0004*(a != d) | - 0x0008*(a != e) | 0x0010*(b != c) | 0x0020*(b != d) | - 0x0040*(b != e) | 0x0080*(c != d) | 0x0100*(c != e) | - 0x0200*(d != e)) - res = interpret(f, [0]) - assert res == ~0x0004 & 0x3ff - res = interpret(f, [1]) - assert res == ~0x0020 & 0x3ff - res = interpret(f, [2]) - assert res == ~0x0100 & 0x3ff - res = interpret(f, [3]) - assert res == ~0x0200 & 0x3ff - -def test_hash_preservation(): - class C: - pass - class D(C): - pass - c = C() - d = D() - def f(): - d2 = D() - x = hash(d2) == id(d2) # xxx check for this CPython peculiarity for now - return x, hash(c)+hash(d) + d = D() + def f(): + d2 = D() + x = hash(d2) == id(d2) # xxx check for this CPython peculiarity for now + return x, hash(c)+hash(d) + + res = interpret(f, [], type_system=self.ts) + + assert res.item0 == True + assert res.item1 == intmask(hash(c)+hash(d)) + + def test_type(self): + class A: + pass + class B(A): + pass + def g(a): + return type(a) + def f(i): + if i > 0: + a = A() + elif i < 0: + a = B() + else: + a = None + return g(a) is A # should type(None) work? returns None for now + res = interpret(f, [1], type_system=self.ts) + assert res is True + res = interpret(f, [-1], type_system=self.ts) + assert res is False + res = interpret(f, [0], type_system=self.ts) + assert res is False + + def test_void_fnptr(self): + def g(): + return 42 + def f(): + e = EmptyBase() + e.attr = g + return e.attr() + res = interpret(f, [], type_system=self.ts) + assert res == 42 + + def test_getattr_on_classes(self): + class A: + def meth(self): + return self.value + 42 + class B(A): + def meth(self): + shouldnt**be**seen + class C(B): + def meth(self): + return self.value - 1 + def pick_class(i): + if i > 0: + return A + else: + return C + def f(i): + meth = pick_class(i).meth + x = C() + x.value = 12 + return meth(x) # calls A.meth or C.meth, completely ignores B.meth + res = interpret(f, [1], type_system=self.ts) + assert res == 54 + res = interpret(f, [0], type_system=self.ts) + assert res == 11 + + def test_constant_bound_method(self): + class C: + value = 1 + def meth(self): + return self.value + meth = C().meth + def f(): + return meth() + res = interpret(f, [], type_system=self.ts) + assert res == 1 + + + +class TestLltype(BaseTestRclass): - res = interpret(f, []) + ts = "lltype" - assert res.item0 == True - assert res.item1 == intmask(hash(c)+hash(d)) + def test__del__(self): + class A(object): + def __init__(self): + self.a = 2 + def __del__(self): + self.a = 3 + def f(): + a = A() + return a.a + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper().specialize() + graph = graphof(t, f) + TYPE = graph.startblock.operations[0].args[0].value + RTTI = getRuntimeTypeInfo(TYPE) + queryptr = RTTI._obj.query_funcptr # should not raise + destrptr = RTTI._obj.destructor_funcptr + assert destrptr is not None -def test_type(): - class A: - pass - class B(A): - pass - def g(a): - return type(a) - def f(i): - if i > 0: + def test_del_inheritance(self): + class State: + pass + s = State() + s.a_dels = 0 + s.b_dels = 0 + class A(object): + def __del__(self): + s.a_dels += 1 + class B(A): + def __del__(self): + s.b_dels += 1 + class C(A): + pass + def f(): + A() + B() + C() + A() + B() + C() + return s.a_dels * 10 + s.b_dels + res = f() + assert res == 42 + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper().specialize() + graph = graphof(t, f) + TYPEA = graph.startblock.operations[0].args[0].value + RTTIA = getRuntimeTypeInfo(TYPEA) + TYPEB = graph.startblock.operations[3].args[0].value + RTTIB = getRuntimeTypeInfo(TYPEB) + TYPEC = graph.startblock.operations[6].args[0].value + RTTIC = getRuntimeTypeInfo(TYPEC) + queryptra = RTTIA._obj.query_funcptr # should not raise + queryptrb = RTTIB._obj.query_funcptr # should not raise + queryptrc = RTTIC._obj.query_funcptr # should not raise + destrptra = RTTIA._obj.destructor_funcptr + destrptrb = RTTIB._obj.destructor_funcptr + destrptrc = RTTIC._obj.destructor_funcptr + assert destrptra == destrptrc + assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] + assert destrptra is not None + assert destrptrb is not None + +class TestOotype(BaseTestRclass): + + ts = "ootype" + + def test__del__(self): + class A(object): + def __init__(self): + self.a = 2 + def __del__(self): + self.a = 3 + def f(): a = A() - elif i < 0: - a = B() - else: - a = None - return g(a) is A # should type(None) work? returns None for now - res = interpret(f, [1]) - assert res is True - res = interpret(f, [-1]) - assert res is False - res = interpret(f, [0]) - assert res is False + return a.a + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper(type_system=self.ts).specialize() + graph = graphof(t, f) + TYPE = graph.startblock.operations[0].args[0].value + meth = TYPE._lookup("o__del___variant0") + assert meth.finalizer + + def test_del_inheritance(self): + class State: + pass + s = State() + s.a_dels = 0 + s.b_dels = 0 + class A(object): + def __del__(self): + s.a_dels += 1 + class B(A): + def __del__(self): + s.b_dels += 1 + class C(A): + pass + def f(): + A() + B() + C() + A() + B() + C() + return s.a_dels * 10 + s.b_dels + res = f() + assert res == 42 + t = TranslationContext() + t.buildannotator().build_types(f, []) + t.buildrtyper(type_system=self.ts).specialize() + graph = graphof(t, f) + TYPEA = graph.startblock.operations[0].args[0].value + TYPEB = graph.startblock.operations[2].args[0].value + TYPEC = graph.startblock.operations[4].args[0].value + destra = TYPEA._lookup("o__del___variant0") + destrb = TYPEB._lookup("o__del___variant0") + destrc = TYPEC._lookup("o__del___variant0") + assert destra == destrc + assert destrb is not None + assert destra is not None -def test_void_fnptr(): - def g(): - return 42 - def f(): - e = EmptyBase() - e.attr = g - return e.attr() - res = interpret(f, []) - assert res == 42 - -def test_getattr_on_classes(): - class A: - def meth(self): - return self.value + 42 - class B(A): - def meth(self): - shouldnt**be**seen - class C(B): - def meth(self): - return self.value - 1 - def pick_class(i): - if i > 0: - return A - else: - return C - def f(i): - meth = pick_class(i).meth - x = C() - x.value = 12 - return meth(x) # calls A.meth or C.meth, completely ignores B.meth - res = interpret(f, [1]) - assert res == 54 - res = interpret(f, [0]) - assert res == 11 - -def test_constant_bound_method(): - class C: - value = 1 - def meth(self): - return self.value - meth = C().meth - def f(): - return meth() - res = interpret(f, []) - assert res == 1 - -def test__del__(): - class A(object): - def __init__(self): - self.a = 2 - def __del__(self): - self.a = 3 - def f(): - a = A() - return a.a - t = TranslationContext() - t.buildannotator().build_types(f, []) - t.buildrtyper().specialize() - graph = graphof(t, f) - TYPE = graph.startblock.operations[0].args[0].value - RTTI = getRuntimeTypeInfo(TYPE) - queryptr = RTTI._obj.query_funcptr # should not raise - destrptr = RTTI._obj.destructor_funcptr - assert destrptr is not None - - -def test_del_inheritance(): - class State: - pass - s = State() - s.a_dels = 0 - s.b_dels = 0 - class A(object): - def __del__(self): - s.a_dels += 1 - class B(A): - def __del__(self): - s.b_dels += 1 - class C(A): - pass - def f(): - A() - B() - C() - A() - B() - C() - return s.a_dels * 10 + s.b_dels - res = f() - assert res == 42 - t = TranslationContext() - t.buildannotator().build_types(f, []) - t.buildrtyper().specialize() - graph = graphof(t, f) - TYPEA = graph.startblock.operations[0].args[0].value - RTTIA = getRuntimeTypeInfo(TYPEA) - TYPEB = graph.startblock.operations[3].args[0].value - RTTIB = getRuntimeTypeInfo(TYPEB) - TYPEC = graph.startblock.operations[6].args[0].value - RTTIC = getRuntimeTypeInfo(TYPEC) - queryptra = RTTIA._obj.query_funcptr # should not raise - queryptrb = RTTIB._obj.query_funcptr # should not raise - queryptrc = RTTIC._obj.query_funcptr # should not raise - destrptra = RTTIA._obj.destructor_funcptr - destrptrb = RTTIB._obj.destructor_funcptr - destrptrc = RTTIC._obj.destructor_funcptr - assert destrptra == destrptrc - assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] - assert destrptra is not None - assert destrptrb is not None Modified: pypy/branch/njriley-trans/pypy/rpython/test/test_rgenop.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/test/test_rgenop.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/test/test_rgenop.py Fri Mar 10 06:12:02 2006 @@ -143,3 +143,19 @@ assert isinstance(c, flowmodel.Constant) assert c.concretetype == lltype.Void assert c.value == None + +def test_rtype_revealcosnt(): + def hide_and_reveal(v): + gv = genconst(v) + return revealconst(lltype.Signed, gv) + res = interpret(hide_and_reveal, [42]) + assert res == 42 + + S = lltype.GcStruct('s', ('x', lltype.Signed)) + S_PTR = lltype.Ptr(S) + def hide_and_reveal_p(p): + gv = genconst(p) + return revealconst(S_PTR, gv) + s = malloc(S) + res = interpret(hide_and_reveal_p, [s]) + assert res == s Modified: pypy/branch/njriley-trans/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/test/test_rpbc.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/test/test_rpbc.py Fri Mar 10 06:12:02 2006 @@ -3,31 +3,6 @@ from pypy.rpython.test.test_llinterp import interpret -def test_easy_call(): - def f(x): - return x+1 - def g(y): - return f(y+2) - res = interpret(g, [5]) - assert res == 8 - -def test_multiple_call(): - def f1(x): - return x+1 - def f2(x): - return x+2 - def g(y): - if y < 0: - f = f1 - else: - f = f2 - return f(y+3) - res = interpret(g, [-1]) - assert res == 3 - res = interpret(g, [1]) - assert res == 6 - - class MyBase: def m(self, x): return self.z + x @@ -40,44 +15,6 @@ def m(self, x, y): return x*y -def test_method_call(): - def f(a, b): - obj = MyBase() - obj.z = a - return obj.m(b) - res = interpret(f, [4, 5]) - assert res == 9 - -def test_virtual_method_call(): - def f(a, b): - if a > 0: - obj = MyBase() - else: - obj = MySubclass() - obj.z = a - return obj.m(b) - res = interpret(f, [1, 2.3]) - assert res == 3.3 - res = interpret(f, [-1, 2.3]) - assert res == -3.3 - -def test_stranger_subclass_1(): - def f1(): - obj = MyStrangerSubclass() - obj.z = 100 - return obj.m(6, 7) - res = interpret(f1, []) - assert res == 42 - -def test_stranger_subclass_2(): - def f2(): - obj = MyStrangerSubclass() - obj.z = 100 - return obj.m(6, 7) + MyBase.m(obj, 58) - res = interpret(f2, []) - assert res == 200 - - class MyBaseWithInit: def __init__(self, a): self.a1 = a @@ -87,791 +24,1097 @@ MyBaseWithInit.__init__(self, a) self.b1 = b -def test_class_init(): - def f(a): - instance = MyBaseWithInit(a) - return instance.a1 - assert interpret(f, [5]) == 5 - -def test_class_init_w_kwds(): - def f(a): - instance = MyBaseWithInit(a=a) - return instance.a1 - assert interpret(f, [5]) == 5 - -def test_class_init_2(): - def f(a, b): - instance = MySubclassWithInit(a, b) - return instance.a1 * instance.b1 - assert interpret(f, [6, 7]) == 42 - -def test_class_init_2_w_kwds(): - def f(a, b): - instance = MySubclassWithInit(a, b=b) - return instance.a1 * instance.b1 - assert interpret(f, [6, 7]) == 42 - -def test_class_calling_init(): - def f(): - instance = MySubclassWithInit(1, 2) - instance.__init__(3, 4) - return instance.a1 * instance.b1 - assert interpret(f, []) == 12 - - class Freezing: def _freeze_(self): return True def mymethod(self, y): return self.x + y -def test_freezing(): - fr1 = Freezing() - fr2 = Freezing() - fr1.x = 5 - fr2.x = 6 - def g(fr): - return fr.x - def f(n): - if n > 0: - fr = fr1 - elif n < 0: - fr = fr2 - else: - fr = None - return g(fr) - res = interpret(f, [1]) - assert res == 5 - res = interpret(f, [-1]) - assert res == 6 -def test_call_frozen_pbc_simple(): - fr1 = Freezing() - fr1.x = 5 - def f(n): - return fr1.mymethod(n) - res = interpret(f, [6]) - assert res == 11 - -def test_call_frozen_pbc_simple_w_kwds(): - fr1 = Freezing() - fr1.x = 5 - def f(n): - return fr1.mymethod(y=n) - res = interpret(f, [6]) - assert res == 11 - -def test_call_frozen_pbc_multiple(): - fr1 = Freezing() - fr2 = Freezing() - fr1.x = 5 - fr2.x = 6 - def f(n): - if n > 0: - fr = fr1 - else: - fr = fr2 - return fr.mymethod(n) - res = interpret(f, [1]) - assert res == 6 - res = interpret(f, [-1]) - assert res == 5 +class BaseTestRPBC: -def test_call_frozen_pbc_multiple_w_kwds(): - fr1 = Freezing() - fr2 = Freezing() - fr1.x = 5 - fr2.x = 6 - def f(n): - if n > 0: - fr = fr1 - else: - fr = fr2 - return fr.mymethod(y=n) - res = interpret(f, [1]) - assert res == 6 - res = interpret(f, [-1]) - assert res == 5 + def test_easy_call(self): + def f(x): + return x+1 + def g(y): + return f(y+2) + res = interpret(g, [5], type_system=self.ts) + assert res == 8 -def test_is_among_frozen(): - fr1 = Freezing() - fr2 = Freezing() - def givefr1(): - return fr1 - def givefr2(): - return fr2 - def f(i): - if i == 1: - fr = givefr1() - else: - fr = givefr2() - return fr is fr1 - res = interpret(f, [0]) - assert res is False - res = interpret(f, [1]) - assert res is True - -def test_unbound_method(): - def f(): - inst = MySubclass() - inst.z = 40 - return MyBase.m(inst, 2) - res = interpret(f, []) - assert res == 42 - -def test_call_defaults(): - def g(a, b=2, c=3): - return a+b+c - def f1(): - return g(1) - def f2(): - return g(1, 10) - def f3(): - return g(1, 10, 100) - res = interpret(f1, []) - assert res == 1+2+3 - res = interpret(f2, []) - assert res == 1+10+3 - res = interpret(f3, []) - assert res == 1+10+100 - -def test_call_memoized_function(): - fr1 = Freezing() - fr2 = Freezing() - def getorbuild(key): - a = 1 - if key is fr1: - result = eval("a+2") - else: - result = eval("a+6") - return result - getorbuild._annspecialcase_ = "specialize:memo" - - def f1(i): - if i > 0: - fr = fr1 - else: - fr = fr2 - return getorbuild(fr) + def test_multiple_call(self): + def f1(x): + return x+1 + def f2(x): + return x+2 + def g(y): + if y < 0: + f = f1 + else: + f = f2 + return f(y+3) + res = interpret(g, [-1], type_system=self.ts) + assert res == 3 + res = interpret(g, [1], type_system=self.ts) + assert res == 6 - res = interpret(f1, [0]) - assert res == 7 - res = interpret(f1, [1]) - assert res == 3 - -def test_call_memoized_function_with_bools(): - fr1 = Freezing() - fr2 = Freezing() - def getorbuild(key, flag1, flag2): - a = 1 - if key is fr1: - result = eval("a+2") - else: - result = eval("a+6") - if flag1: - result += 100 - if flag2: - result += 1000 - return result - getorbuild._annspecialcase_ = "specialize:memo" - - def f1(i): - if i > 0: - fr = fr1 - else: - fr = fr2 - return getorbuild(fr, i % 2 == 0, i % 3 == 0) - for n in [0, 1, 2, -3, 6]: - res = interpret(f1, [n]) - assert res == f1(n) - -def test_call_memoized_cache(): - - # this test checks that we add a separate field - # per specialization and also it uses a subclass of - # the standard pypy.tool.cache.Cache - - from pypy.tool.cache import Cache - fr1 = Freezing() - fr2 = Freezing() - - class Cache1(Cache): - def _build(self, key): - "NOT_RPYTHON" - if key is fr1: - return fr2 + def test_method_call(self): + def f(a, b): + obj = MyBase() + obj.z = a + return obj.m(b) + res = interpret(f, [4, 5], type_system=self.ts) + assert res == 9 + + def test_virtual_method_call(self): + def f(a, b): + if a > 0: + obj = MyBase() else: - return fr1 - - class Cache2(Cache): - def _build(self, key): - "NOT_RPYTHON" + obj = MySubclass() + obj.z = a + return obj.m(b) + res = interpret(f, [1, 2.3], type_system=self.ts) + assert res == 3.3 + res = interpret(f, [-1, 2.3], type_system=self.ts) + assert res == -3.3 + + def test_stranger_subclass_1(self): + def f1(): + obj = MyStrangerSubclass() + obj.z = 100 + return obj.m(6, 7) + res = interpret(f1, [], type_system=self.ts) + assert res == 42 + + def test_stranger_subclass_2(self): + def f2(): + obj = MyStrangerSubclass() + obj.z = 100 + return obj.m(6, 7) + MyBase.m(obj, 58) + res = interpret(f2, [], type_system=self.ts) + assert res == 200 + + + def test_class_init(self): + def f(a): + instance = MyBaseWithInit(a) + return instance.a1 + assert interpret(f, [5], type_system=self.ts) == 5 + + def test_class_init_2(self): + def f(a, b): + instance = MySubclassWithInit(a, b) + return instance.a1 * instance.b1 + assert interpret(f, [6, 7], type_system=self.ts) == 42 + + def test_class_calling_init(self): + def f(): + instance = MySubclassWithInit(1, 2) + instance.__init__(3, 4) + return instance.a1 * instance.b1 + assert interpret(f, [], type_system=self.ts) == 12 + + def test_class_init_w_kwds(self): + def f(a): + instance = MyBaseWithInit(a=a) + return instance.a1 + assert interpret(f, [5], type_system=self.ts) == 5 + + def test_class_init_2_w_kwds(self): + def f(a, b): + instance = MySubclassWithInit(a, b=b) + return instance.a1 * instance.b1 + assert interpret(f, [6, 7], type_system=self.ts) == 42 + + + def test_freezing(self): + fr1 = Freezing() + fr2 = Freezing() + fr1.x = 5 + fr2.x = 6 + def g(fr): + return fr.x + def f(n): + if n > 0: + fr = fr1 + elif n < 0: + fr = fr2 + else: + fr = None + return g(fr) + res = interpret(f, [1], type_system=self.ts) + assert res == 5 + res = interpret(f, [-1], type_system=self.ts) + assert res == 6 + + def test_call_frozen_pbc_simple(self): + fr1 = Freezing() + fr1.x = 5 + def f(n): + return fr1.mymethod(n) + res = interpret(f, [6], type_system=self.ts) + assert res == 11 + + def test_call_frozen_pbc_simple_w_kwds(self): + fr1 = Freezing() + fr1.x = 5 + def f(n): + return fr1.mymethod(y=n) + res = interpret(f, [6], type_system=self.ts) + assert res == 11 + + def test_call_frozen_pbc_multiple(self): + fr1 = Freezing() + fr2 = Freezing() + fr1.x = 5 + fr2.x = 6 + def f(n): + if n > 0: + fr = fr1 + else: + fr = fr2 + return fr.mymethod(n) + res = interpret(f, [1], type_system=self.ts) + assert res == 6 + res = interpret(f, [-1], type_system=self.ts) + assert res == 5 + + def test_call_frozen_pbc_multiple_w_kwds(self): + fr1 = Freezing() + fr2 = Freezing() + fr1.x = 5 + fr2.x = 6 + def f(n): + if n > 0: + fr = fr1 + else: + fr = fr2 + return fr.mymethod(y=n) + res = interpret(f, [1], type_system=self.ts) + assert res == 6 + res = interpret(f, [-1], type_system=self.ts) + assert res == 5 + + def test_is_among_frozen(self): + fr1 = Freezing() + fr2 = Freezing() + def givefr1(): + return fr1 + def givefr2(): + return fr2 + def f(i): + if i == 1: + fr = givefr1() + else: + fr = givefr2() + return fr is fr1 + res = interpret(f, [0], type_system=self.ts) + assert res is False + res = interpret(f, [1], type_system=self.ts) + assert res is True + + def test_unbound_method(self): + def f(): + inst = MySubclass() + inst.z = 40 + return MyBase.m(inst, 2) + res = interpret(f, [], type_system=self.ts) + assert res == 42 + + def test_call_defaults(self): + def g(a, b=2, c=3): + return a+b+c + def f1(): + return g(1) + def f2(): + return g(1, 10) + def f3(): + return g(1, 10, 100) + res = interpret(f1, [], type_system=self.ts) + assert res == 1+2+3 + res = interpret(f2, [], type_system=self.ts) + assert res == 1+10+3 + res = interpret(f3, [], type_system=self.ts) + assert res == 1+10+100 + + def test_call_memoized_function(self): + fr1 = Freezing() + fr2 = Freezing() + def getorbuild(key): a = 1 if key is fr1: result = eval("a+2") else: result = eval("a+6") return result + getorbuild._annspecialcase_ = "specialize:memo" - cache1 = Cache1() - cache2 = Cache2() + def f1(i): + if i > 0: + fr = fr1 + else: + fr = fr2 + return getorbuild(fr) - def f1(i): - if i > 0: - fr = fr1 - else: - fr = fr2 - newfr = cache1.getorbuild(fr) - return cache2.getorbuild(newfr) - - res = interpret(f1, [0], view=0, viewbefore=0) - assert res == 3 - res = interpret(f1, [1]) - assert res == 7 - -def test_call_memo_with_class(): - class A: pass - class FooBar(A): pass - def memofn(cls): - return len(cls.__name__) - memofn._annspecialcase_ = "specialize:memo" - - def f1(i): - if i == 1: - cls = A - else: - cls = FooBar - FooBar() # make sure we have ClassDefs - return memofn(cls) - res = interpret(f1, [1]) - assert res == 1 - res = interpret(f1, [2]) - assert res == 6 + res = interpret(f1, [0], type_system=self.ts) + assert res == 7 + res = interpret(f1, [1], type_system=self.ts) + assert res == 3 + + def test_call_memoized_function_with_bools(self): + fr1 = Freezing() + fr2 = Freezing() + def getorbuild(key, flag1, flag2): + a = 1 + if key is fr1: + result = eval("a+2") + else: + result = eval("a+6") + if flag1: + result += 100 + if flag2: + result += 1000 + return result + getorbuild._annspecialcase_ = "specialize:memo" -def test_call_memo_with_single_value(): - class A: pass - def memofn(cls): - return len(cls.__name__) - memofn._annspecialcase_ = "specialize:memo" - - def f1(): - A() # make sure we have a ClassDef - return memofn(A) - res = interpret(f1, []) - assert res == 1 + def f1(i): + if i > 0: + fr = fr1 + else: + fr = fr2 + return getorbuild(fr, i % 2 == 0, i % 3 == 0) -def test_rpbc_bound_method_static_call(): - class R: - def meth(self): - return 0 - r = R() - m = r.meth - def fn(): - return m() - res = interpret(fn, []) - assert res == 0 - -def test_rpbc_bound_method_static_call_w_kwds(): - class R: - def meth(self, x): - return x - r = R() - m = r.meth - def fn(): - return m(x=3) - res = interpret(fn, []) - assert res == 3 - - -def test_constant_return_disagreement(): - class R: - def meth(self): - return 0 - r = R() - def fn(): - return r.meth() - res = interpret(fn, []) - assert res == 0 - -def test_None_is_false(): - def fn(i): - return bool([None, fn][i]) - res = interpret(fn, [1]) - assert res is True - res = interpret(fn, [0]) - assert res is False - -def test_classpbc_getattr(): - class A: - myvalue = 123 - class B(A): - myvalue = 456 - def f(i): - return [A,B][i].myvalue - res = interpret(f, [0]) - assert res == 123 - res = interpret(f, [1]) - assert res == 456 - -def test_function_or_None(): - def g1(): - return 42 - def f(i): - g = None - if i > 5: - g = g1 - if i > 6: - return g() - else: - return 12 + for n in [0, 1, 2, -3, 6]: + res = interpret(f1, [n], type_system=self.ts) + assert res == f1(n) + + def test_call_memoized_cache(self): + + # this test checks that we add a separate field + # per specialization and also it uses a subclass of + # the standard pypy.tool.cache.Cache + + from pypy.tool.cache import Cache + fr1 = Freezing() + fr2 = Freezing() + + class Cache1(Cache): + def _build(self, key): + "NOT_RPYTHON" + if key is fr1: + return fr2 + else: + return fr1 + + class Cache2(Cache): + def _build(self, key): + "NOT_RPYTHON" + a = 1 + if key is fr1: + result = eval("a+2") + else: + result = eval("a+6") + return result + + cache1 = Cache1() + cache2 = Cache2() + + def f1(i): + if i > 0: + fr = fr1 + else: + fr = fr2 + newfr = cache1.getorbuild(fr) + return cache2.getorbuild(newfr) + + res = interpret(f1, [0], type_system=self.ts) + assert res == 3 + res = interpret(f1, [1], type_system=self.ts) + assert res == 7 + + def test_call_memo_with_single_value(self): + class A: pass + def memofn(cls): + return len(cls.__name__) + memofn._annspecialcase_ = "specialize:memo" + + def f1(): + A() # make sure we have a ClassDef + return memofn(A) + res = interpret(f1, [], type_system=self.ts) + assert res == 1 + + def test_call_memo_with_class(self): + class A: pass + class FooBar(A): pass + def memofn(cls): + return len(cls.__name__) + memofn._annspecialcase_ = "specialize:memo" + + def f1(i): + if i == 1: + cls = A + else: + cls = FooBar + FooBar() # make sure we have ClassDefs + return memofn(cls) + res = interpret(f1, [1], type_system=self.ts) + assert res == 1 + res = interpret(f1, [2], type_system=self.ts) + assert res == 6 + + def test_rpbc_bound_method_static_call(self): + class R: + def meth(self): + return 0 + r = R() + m = r.meth + def fn(): + return m() + res = interpret(fn, [], type_system=self.ts) + assert res == 0 + + def test_rpbc_bound_method_static_call_w_kwds(self): + class R: + def meth(self, x): + return x + r = R() + m = r.meth + def fn(): + return m(x=3) + res = interpret(fn, [], type_system=self.ts) + assert res == 3 + + + def test_constant_return_disagreement(self): + class R: + def meth(self): + return 0 + r = R() + def fn(): + return r.meth() + res = interpret(fn, [], type_system=self.ts) + assert res == 0 + + def test_None_is_false(self): + def fn(i): + if i == 0: + v = None + else: + v = fn + return bool(v) + res = interpret(fn, [1], type_system=self.ts) + assert res is True + res = interpret(fn, [0], type_system=self.ts) + assert res is False + + def test_classpbc_getattr(self): + class A: + myvalue = 123 + class B(A): + myvalue = 456 + def f(i): + if i == 0: + v = A + else: + v = B + return v.myvalue + res = interpret(f, [0], type_system=self.ts) + assert res == 123 + res = interpret(f, [1], type_system=self.ts) + assert res == 456 + + def test_function_or_None(self): + def g1(): + return 42 + def f(i): + g = None + if i > 5: + g = g1 + if i > 6: + return g() + else: + return 12 - res = interpret(f, [0]) - assert res == 12 - res = interpret(f, [6]) - assert res == 12 - res = interpret(f, [7]) - assert res == 42 - -def test_classdef_getattr(): - class A: - myvalue = 123 - class B(A): - myvalue = 456 - def f(i): - B() # for A and B to have classdefs - return [A,B][i].myvalue - res = interpret(f, [0]) - assert res == 123 - res = interpret(f, [1]) - assert res == 456 - -def test_call_classes(): - class A: pass - class B(A): pass - def f(i): - if i == 1: - cls = B - else: - cls = A - return cls() - res = interpret(f, [0]) - assert res.super.typeptr.name[0] == 'A' - res = interpret(f, [1]) - assert res.super.typeptr.name[0] == 'B' - -def test_call_classes_with_init2(): - class A: - def __init__(self, z): - self.z = z - class B(A): - def __init__(self, z, x=42): - A.__init__(self, z) - self.extra = x - def f(i, z): - if i == 1: - cls = B - else: - cls = A - return cls(z) - res = interpret(f, [0, 5]) - assert res.super.typeptr.name[0] == 'A' - assert res.inst_z == 5 - res = interpret(f, [1, -7645]) - assert res.super.typeptr.name[0] == 'B' - assert res.inst_z == -7645 - assert res._obj._parentstructure().inst_extra == 42 - -def test_call_starargs(): - def g(x=-100, *arg): - return x + len(arg) - def f(i): - if i == -1: - return g() - elif i == 0: - return g(4) - elif i == 1: - return g(5, 15) - elif i == 2: - return g(7, 17, 27) - else: - return g(10, 198, 1129, 13984) - res = interpret(f, [-1]) - assert res == -100 - res = interpret(f, [0]) - assert res == 4 - res = interpret(f, [1]) - assert res == 6 - res = interpret(f, [2]) - assert res == 9 - res = interpret(f, [3]) - assert res == 13 - -def test_conv_from_None(): - class A(object): pass - def none(): - return None - - def f(i): - if i == 1: - return none() - else: - return "ab" - res = interpret(f, [1]) - assert not res - res = interpret(f, [0]) - assert ''.join(res.chars) == "ab" + res = interpret(f, [0], type_system=self.ts) + assert res == 12 + res = interpret(f, [6], type_system=self.ts) + assert res == 12 + res = interpret(f, [7], type_system=self.ts) + assert res == 42 + + def test_classdef_getattr(self): + class A: + myvalue = 123 + class B(A): + myvalue = 456 + def f(i): + B() # for A and B to have classdefs + if i == 0: + v = A + else: + v = B + return v.myvalue + res = interpret(f, [0], type_system=self.ts) + assert res == 123 + res = interpret(f, [1], type_system=self.ts) + assert res == 456 + + def test_call_classes(self): + class A: pass + class B(A): pass + def f(i): + if i == 1: + cls = B + else: + cls = A + return cls() + res = interpret(f, [0], type_system=self.ts) + assert self.class_name(res) == 'A' + res = interpret(f, [1], type_system=self.ts) + assert self.class_name(res) == 'B' + + def test_call_classes_with_init2(self): + class A: + def __init__(self, z): + self.z = z + class B(A): + def __init__(self, z, x=42): + A.__init__(self, z) + self.extra = x + def f(i, z): + if i == 1: + cls = B + else: + cls = A + return cls(z) + res = interpret(f, [0, 5], type_system=self.ts) + assert self.class_name(res) == 'A' + assert self.read_attr(res, "z") == 5 + res = interpret(f, [1, -7645], type_system=self.ts) + assert self.class_name(res) == 'B' + assert self.read_attr(res, "z") == -7645 + assert self.read_attr(res, "extra") == 42 + + def test_conv_from_None(self): + class A(object): pass + def none(): + return None - def g(i): - if i == 1: - return none() - else: - return A() - res = interpret(g, [1]) - assert not res - res = interpret(g, [0]) - assert res.super.typeptr.name[0] == 'A' + def f(i): + if i == 1: + return none() + else: + return "ab" + res = interpret(f, [1], type_system=self.ts) + assert not res + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == "ab" + + def g(i): + if i == 1: + return none() + else: + return A() + res = interpret(g, [1], type_system=self.ts) + assert not res + res = interpret(g, [0], type_system=self.ts) + assert self.class_name(res) == 'A' -def test_conv_from_classpbcset_to_larger(): - class A(object): pass - class B(A): pass - class C(A): pass - - def a(): - return A - def b(): - return B - - - def g(i): - if i == 1: - cls = a() - else: - cls = b() - return cls() - - res = interpret(g, [0]) - assert res.super.typeptr.name[0] == 'B' - res = interpret(g, [1]) - assert res.super.typeptr.name[0] == 'A' - - def bc(j): - if j == 1: + def test_conv_from_classpbcset_to_larger(self): + class A(object): pass + class B(A): pass + class C(A): pass + + def a(): + return A + def b(): return B - else: - return C - - def g(i, j): - if i == 1: - cls = a() - else: - cls = bc(j) - return cls() + - res = interpret(g, [0, 0]) - assert res.super.typeptr.name[0] == 'C' - res = interpret(g, [0, 1]) - assert res.super.typeptr.name[0] == 'B' - res = interpret(g, [1, 0]) - assert res.super.typeptr.name[0] == 'A' - -def test_call_keywords(): - def g(a=1, b=2, c=3): - return 100*a+10*b+c - - def f(i): - if i == 0: - return g(a=7) - elif i == 1: - return g(b=11) - elif i == 2: - return g(c=13) - elif i == 3: - return g(a=7, b=11) - elif i == 4: - return g(b=7, a=11) - elif i == 5: - return g(a=7, c=13) - elif i == 6: - return g(c=7, a=13) - elif i == 7: - return g(a=7,b=11,c=13) - elif i == 8: - return g(a=7,c=11,b=13) - elif i == 9: - return g(b=7,a=11,c=13) - else: - return g(b=7,c=11,a=13) + def g(i): + if i == 1: + cls = a() + else: + cls = b() + return cls() - for i in range(11): - res = interpret(f, [i]) - assert res == f(i) - -def test_call_star_and_keywords(): - def g(a=1, b=2, c=3): - return 100*a+10*b+c - - def f(i, x): - if x == 1: - j = 11 - else: - j = 22 - if i == 0: - return g(7) - elif i == 1: - return g(7,*(j,)) - elif i == 2: - return g(7,*(11,j)) - elif i == 3: - return g(a=7) - elif i == 4: - return g(b=7, *(j,)) - elif i == 5: - return g(b=7, c=13, *(j,)) - elif i == 6: - return g(c=7, b=13, *(j,)) - elif i == 7: - return g(c=7,*(j,)) - elif i == 8: - return g(c=7,*(11,j)) - else: - return 0 + res = interpret(g, [0], type_system=self.ts) + assert self.class_name(res) == 'B' + res = interpret(g, [1], type_system=self.ts) + assert self.class_name(res) == 'A' + + def bc(j): + if j == 1: + return B + else: + return C - for i in range(9): - for x in range(1): - res = interpret(f, [i, x]) - assert res == f(i, x) - -def test_call_star_and_keywords_starargs(): - def g(a=1, b=2, c=3, *rest): - return 1000*len(rest)+100*a+10*b+c - - def f(i, x): - if x == 1: - j = 13 - else: - j = 31 - if i == 0: - return g() - elif i == 1: - return g(*(j,)) - elif i == 2: - return g(*(13, j)) - elif i == 3: - return g(*(13, j, 19)) - elif i == 4: - return g(*(13, j, 19, 21)) - elif i == 5: - return g(7) - elif i == 6: - return g(7, *(j,)) - elif i == 7: - return g(7, *(13, j)) - elif i == 8: - return g(7, *(13, 17, j)) - elif i == 9: - return g(7, *(13, 17, j, 21)) - elif i == 10: - return g(7, 9) - elif i == 11: - return g(7, 9, *(j,)) - elif i == 12: - return g(7, 9, *(j, 17)) - elif i == 13: - return g(7, 9, *(13, j, 19)) - elif i == 14: - return g(7, 9, 11) - elif i == 15: - return g(7, 9, 11, *(j,)) - elif i == 16: - return g(7, 9, 11, *(13, j)) - elif i == 17: - return g(7, 9, 11, *(13, 17, j)) - elif i == 18: - return g(7, 9, 11, 2) - elif i == 19: - return g(7, 9, 11, 2, *(j,)) - elif i == 20: - return g(7, 9, 11, 2, *(13, j)) - else: - return 0 + def g(i, j): + if i == 1: + cls = a() + else: + cls = bc(j) + return cls() - for i in range(21): - for x in range(1): - res = interpret(f, [i, x]) - assert res == f(i, x) - -def test_conv_from_funcpbcset_to_larger(): - def f1(): - return 7 - def f2(): - return 11 - def f3(): - return 13 - - def a(): - return f1 - def b(): - return f2 - + res = interpret(g, [0, 0], type_system=self.ts) + assert self.class_name(res) == 'C' + res = interpret(g, [0, 1], type_system=self.ts) + assert self.class_name(res) == 'B' + res = interpret(g, [1, 0], type_system=self.ts) + assert self.class_name(res) == 'A' + + def test_call_starargs(self): + def g(x=-100, *arg): + return x + len(arg) + def f(i): + if i == -1: + return g() + elif i == 0: + return g(4) + elif i == 1: + return g(5, 15) + elif i == 2: + return g(7, 17, 27) + else: + return g(10, 198, 1129, 13984) + res = interpret(f, [-1], type_system=self.ts) + assert res == -100 + res = interpret(f, [0], type_system=self.ts) + assert res == 4 + res = interpret(f, [1], type_system=self.ts) + assert res == 6 + res = interpret(f, [2], type_system=self.ts) + assert res == 9 + res = interpret(f, [3], type_system=self.ts) + assert res == 13 + + def test_call_keywords(self): + def g(a=1, b=2, c=3): + return 100*a+10*b+c + + def f(i): + if i == 0: + return g(a=7) + elif i == 1: + return g(b=11) + elif i == 2: + return g(c=13) + elif i == 3: + return g(a=7, b=11) + elif i == 4: + return g(b=7, a=11) + elif i == 5: + return g(a=7, c=13) + elif i == 6: + return g(c=7, a=13) + elif i == 7: + return g(a=7,b=11,c=13) + elif i == 8: + return g(a=7,c=11,b=13) + elif i == 9: + return g(b=7,a=11,c=13) + else: + return g(b=7,c=11,a=13) - def g(i): - if i == 1: - f = a() - else: - f = b() - return f() + for i in range(11): + res = interpret(f, [i], type_system=self.ts) + assert res == f(i) + + def test_call_star_and_keywords(self): + def g(a=1, b=2, c=3): + return 100*a+10*b+c + + def f(i, x): + if x == 1: + j = 11 + else: + j = 22 + if i == 0: + return g(7) + elif i == 1: + return g(7,*(j,)) + elif i == 2: + return g(7,*(11,j)) + elif i == 3: + return g(a=7) + elif i == 4: + return g(b=7, *(j,)) + elif i == 5: + return g(b=7, c=13, *(j,)) + elif i == 6: + return g(c=7, b=13, *(j,)) + elif i == 7: + return g(c=7,*(j,)) + elif i == 8: + return g(c=7,*(11,j)) + else: + return 0 - res = interpret(g, [0]) - assert res == 11 - res = interpret(g, [1]) - assert res == 7 + for i in range(9): + for x in range(1): + res = interpret(f, [i, x], type_system=self.ts) + assert res == f(i, x) + + def test_call_star_and_keywords_starargs(self): + def g(a=1, b=2, c=3, *rest): + return 1000*len(rest)+100*a+10*b+c + + def f(i, x): + if x == 1: + j = 13 + else: + j = 31 + if i == 0: + return g() + elif i == 1: + return g(*(j,)) + elif i == 2: + return g(*(13, j)) + elif i == 3: + return g(*(13, j, 19)) + elif i == 4: + return g(*(13, j, 19, 21)) + elif i == 5: + return g(7) + elif i == 6: + return g(7, *(j,)) + elif i == 7: + return g(7, *(13, j)) + elif i == 8: + return g(7, *(13, 17, j)) + elif i == 9: + return g(7, *(13, 17, j, 21)) + elif i == 10: + return g(7, 9) + elif i == 11: + return g(7, 9, *(j,)) + elif i == 12: + return g(7, 9, *(j, 17)) + elif i == 13: + return g(7, 9, *(13, j, 19)) + elif i == 14: + return g(7, 9, 11) + elif i == 15: + return g(7, 9, 11, *(j,)) + elif i == 16: + return g(7, 9, 11, *(13, j)) + elif i == 17: + return g(7, 9, 11, *(13, 17, j)) + elif i == 18: + return g(7, 9, 11, 2) + elif i == 19: + return g(7, 9, 11, 2, *(j,)) + elif i == 20: + return g(7, 9, 11, 2, *(13, j)) + else: + return 0 - def bc(j): - if j == 1: + for i in range(21): + for x in range(1): + res = interpret(f, [i, x], type_system=self.ts) + assert res == f(i, x) + + def test_conv_from_funcpbcset_to_larger(self): + def f1(): + return 7 + def f2(): + return 11 + def f3(): + return 13 + + def a(): + return f1 + def b(): return f2 - else: - return f3 - - def g(i, j): - if i == 1: - cls = a() - else: - cls = bc(j) - return cls() - - res = interpret(g, [0, 0]) - assert res == 13 - res = interpret(g, [0, 1]) - assert res == 11 - res = interpret(g, [1, 0]) - assert res == 7 - -def test_call_special_starargs_method(): - class Star: - def __init__(self, d): - self.d = d - def meth(self, *args): - return self.d + len(args) - - def f(i, j): - s = Star(i) - return s.meth(i, j) + - res = interpret(f, [3, 0]) - assert res == 5 + def g(i): + if i == 1: + f = a() + else: + f = b() + return f() -def test_call_star_method(): - class N: - def __init__(self, d): - self.d = d - def meth(self, a, b): - return self.d + a + b - - def f(i, j): - n = N(i) - return n.meth(*(i, j)) - - res = interpret(f, [3, 7]) - assert res == 13 - -def test_call_star_special_starargs_method(): - class N: - def __init__(self, d): - self.d = d - def meth(self, *args): - return self.d + len(args) - - def f(i, j): - n = N(i) - return n.meth(*(i, j)) + res = interpret(g, [0], type_system=self.ts) + assert res == 11 + res = interpret(g, [1], type_system=self.ts) + assert res == 7 + + def bc(j): + if j == 1: + return f2 + else: + return f3 - res = interpret(f, [3, 0]) - assert res == 5 + def g(i, j): + if i == 1: + cls = a() + else: + cls = bc(j) + return cls() -def test_various_patterns_but_one_signature_method(): - class A: - def meth(self, a, b=0): - raise NotImplementedError - class B(A): - def meth(self, a, b=0): - return a+b + res = interpret(g, [0, 0], type_system=self.ts) + assert res == 13 + res = interpret(g, [0, 1], type_system=self.ts) + assert res == 11 + res = interpret(g, [1, 0], type_system=self.ts) + assert res == 7 + + def test_call_special_starargs_method(self): + class Star: + def __init__(self, d): + self.d = d + def meth(self, *args): + return self.d + len(args) + + def f(i, j): + s = Star(i) + return s.meth(i, j) + + res = interpret(f, [3, 0], type_system=self.ts) + assert res == 5 + + def test_call_star_method(self): + class N: + def __init__(self, d): + self.d = d + def meth(self, a, b): + return self.d + a + b + + def f(i, j): + n = N(i) + return n.meth(*(i, j)) + + res = interpret(f, [3, 7], type_system=self.ts) + assert res == 13 + + def test_call_star_special_starargs_method(self): + class N: + def __init__(self, d): + self.d = d + def meth(self, *args): + return self.d + len(args) + + def f(i, j): + n = N(i) + return n.meth(*(i, j)) + + res = interpret(f, [3, 0], type_system=self.ts) + assert res == 5 + + def test_various_patterns_but_one_signature_method(self): + class A: + def meth(self, a, b=0): + raise NotImplementedError + class B(A): + def meth(self, a, b=0): + return a+b + + class C(A): + def meth(self, a, b=0): + return a*b + def f(i): + if i == 0: + x = B() + else: + x = C() + r1 = x.meth(1) + r2 = x.meth(3, 2) + r3 = x.meth(7, b=11) + return r1+r2+r3 + res = interpret(f, [0], type_system=self.ts) + assert res == 1+3+2+7+11 + res = interpret(f, [1], type_system=self.ts) + assert res == 3*2+11*7 - class C(A): - def meth(self, a, b=0): - return a*b - def f(i): - if i == 0: - x = B() - else: - x = C() - r1 = x.meth(1) - r2 = x.meth(3, 2) - r3 = x.meth(7, b=11) - return r1+r2+r3 - res = interpret(f, [0]) - assert res == 1+3+2+7+11 - res = interpret(f, [1]) - assert res == 3*2+11*7 - -def test_multiple_ll_one_hl_op(): - class E(Exception): - pass - class A(object): - pass - class B(A): - pass - class C(object): - def method(self, x): - if x: - raise E() + def test_multiple_ll_one_hl_op(self): + class E(Exception): + pass + class A(object): + pass + class B(A): + pass + class C(object): + def method(self, x): + if x: + raise E() + else: + return A() + class D(C): + def method(self, x): + if x: + raise E() + else: + return B() + def call(x): + c = D() + c.method(x) + try: + c.method(x + 1) + except E: + pass + c = C() + c.method(x) + try: + return c.method(x + 1) + except E: + return None + res = interpret(call, [0], type_system=self.ts) + + def test_multiple_pbc_with_void_attr(self): + class A: + def _freeze_(self): + return True + a1 = A() + a2 = A() + unique = A() + unique.result = 42 + a1.value = unique + a2.value = unique + def g(a): + return a.value.result + def f(i): + if i == 1: + a = a1 else: - return A() - class D(C): - def method(self, x): - if x: - raise E() - else: - return B() - def call(x): - c = D() - c.method(x) - try: - c.method(x + 1) - except E: + a = a2 + return g(a) + res = interpret(f, [0], type_system=self.ts) + assert res == 42 + res = interpret(f, [1], type_system=self.ts) + assert res == 42 + + def test_function_or_none(self): + def h(y): + return y+84 + def g(y): + return y+42 + def f(x, y): + if x == 1: + func = g + elif x == 2: + func = h + else: + func = None + if func: + return func(y) + return -1 + res = interpret(f, [1, 100], type_system=self.ts) + assert res == 142 + res = interpret(f, [2, 100], type_system=self.ts) + assert res == 184 + res = interpret(f, [3, 100], type_system=self.ts) + assert res == -1 + + def test_pbc_getattr_conversion(self): + fr1 = Freezing() + fr2 = Freezing() + fr3 = Freezing() + fr1.value = 10 + fr2.value = 5 + fr3.value = 2.5 + def pick12(i): + if i > 0: + return fr1 + else: + return fr2 + def pick23(i): + if i > 5: + return fr2 + else: + return fr3 + def f(i): + x = pick12(i) + y = pick23(i) + return x.value, y.value + for i in [0, 5, 10]: + res = interpret(f, [i], type_system=self.ts) + assert type(res.item0) is int # precise + assert type(res.item1) is float + assert res.item0 == f(i)[0] + assert res.item1 == f(i)[1] + + def test_pbc_getattr_conversion_with_classes(self): + class base: pass + class fr1(base): pass + class fr2(base): pass + class fr3(base): pass + fr1.value = 10 + fr2.value = 5 + fr3.value = 2.5 + def pick12(i): + if i > 0: + return fr1 + else: + return fr2 + def pick23(i): + if i > 5: + return fr2 + else: + return fr3 + def f(i): + x = pick12(i) + y = pick23(i) + return x.value, y.value + for i in [0, 5, 10]: + res = interpret(f, [i], type_system=self.ts) + assert type(res.item0) is int # precise + assert type(res.item1) is float + assert res.item0 == f(i)[0] + assert res.item1 == f(i)[1] + + def test_multiple_specialized_functions(self): + def myadder(x, y): # int,int->int or str,str->str + return x+y + def myfirst(x, y): # int,int->int or str,str->str + return x + def mysecond(x, y): # int,int->int or str,str->str + return y + myadder._annspecialcase_ = 'specialize:argtype(0)' + myfirst._annspecialcase_ = 'specialize:argtype(0)' + mysecond._annspecialcase_ = 'specialize:argtype(0)' + def f(i): + if i == 0: + g = myfirst + elif i == 1: + g = mysecond + else: + g = myadder + s = g("hel", "lo") + n = g(40, 2) + return len(s) * n + for i in range(3): + res = interpret(f, [i], type_system=self.ts) + assert res == f(i) + + def test_specialized_method_of_frozen(self): + class space: + def _freeze_(self): + return True + def __init__(self, tag): + self.tag = tag + def wrap(self, x): + if isinstance(x, int): + return self.tag + '< %d >' % x + else: + return self.tag + x + wrap._annspecialcase_ = 'specialize:argtype(1)' + space1 = space("tag1:") + space2 = space("tag2:") + def f(i): + if i == 1: + sp = space1 + else: + sp = space2 + w1 = sp.wrap('hello') + w2 = sp.wrap(42) + return w1 + w2 + res = interpret(f, [1], type_system=self.ts) + assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + + def test_specialized_method(self): + class A: + def __init__(self, tag): + self.tag = tag + def wrap(self, x): + if isinstance(x, int): + return self.tag + '< %d >' % x + else: + return self.tag + x + wrap._annspecialcase_ = 'specialize:argtype(1)' + a1 = A("tag1:") + a2 = A("tag2:") + def f(i): + if i == 1: + sp = a1 + else: + sp = a2 + w1 = sp.wrap('hello') + w2 = sp.wrap(42) + return w1 + w2 + res = interpret(f, [1], type_system=self.ts) + assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' + res = interpret(f, [0], type_system=self.ts) + assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' + + def test_precise_method_call_1(self): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): pass - c = C() - c.method(x) - try: - return c.method(x + 1) - except E: - return None - res = interpret(call, [0]) + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth only, using the default argument + result2 = C().meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234], type_system=self.ts) + assert res == f(i, 1234) + + def test_precise_method_call_2(self): + class A(object): + def meth(self, x=5): + return x+1 + class B(A): + def meth(self, x=5): + return x+2 + class C(A): + def meth(self, x=5): + return x+3 + def f(i, n): + # call both A.meth and B.meth with an explicit argument + if i > 0: + x = A() + else: + x = B() + result1 = x.meth(n) + # now call A.meth and C.meth, using the default argument + if i > 0: + x = C() + else: + x = A() + result2 = x.meth() + return result1 * result2 + for i in [0, 1]: + res = interpret(f, [i, 1234], type_system=self.ts) + assert res == f(i, 1234) -def test_multiple_pbc_with_void_attr(): - class A: - def _freeze_(self): - return True - a1 = A() - a2 = A() - unique = A() - unique.result = 42 - a1.value = unique - a2.value = unique - def g(a): - return a.value.result - def f(i): - if i == 1: - a = a1 - else: - a = a2 - return g(a) - res = interpret(f, [0]) - assert res == 42 - res = interpret(f, [1]) - assert res == 42 + +def test_call_from_list(): + # Don't test with ootype, since it doesn't support lists in a + # coherent way yet. + def f0(n): return n+200 + def f1(n): return n+192 + def f2(n): return n+46 + def f3(n): return n+2987 + def f4(n): return n+217 + lst = [f0, f1, f2, f3, f4] + def f(i, n): + return lst[i](n) + for i in range(5): + res = interpret(f, [i, 1000]) + assert res == f(i, 1000) + + +# We don't care about the following test_hlinvoke tests working on +# ootype. Maybe later. This kind of thing is only used in rdict +# anyway, that will probably have a different kind of implementation +# in ootype. def test_hlinvoke_simple(): def f(a,b): @@ -960,7 +1203,6 @@ res = interp.eval_graph(ll_h_graph, [None, r_f.convert_desc(f2desc), 3]) assert res == 1 - def test_hlinvoke_hltype(): class A(object): def __init__(self, v): @@ -1121,190 +1363,31 @@ res = interp.eval_graph(ll_h_graph, [None, c_f, c_a]) assert typeOf(res) == A_repr.lowleveltype -def test_function_or_none(): - def h(y): - return y+84 - def g(y): - return y+42 - def f(x, y): - d = {1: g, 2:h} - func = d.get(x, None) - if func: - return func(y) - return -1 - res = interpret(f, [1, 100]) - assert res == 142 - res = interpret(f, [2, 100]) - assert res == 184 - res = interpret(f, [3, 100]) - assert res == -1 - -def test_pbc_getattr_conversion(): - fr1 = Freezing() - fr2 = Freezing() - fr3 = Freezing() - fr1.value = 10 - fr2.value = 5 - fr3.value = 2.5 - def pick12(i): - if i > 0: - return fr1 - else: - return fr2 - def pick23(i): - if i > 5: - return fr2 - else: - return fr3 - def f(i): - x = pick12(i) - y = pick23(i) - return x.value, y.value - for i in [0, 5, 10]: - res = interpret(f, [i]) - assert type(res.item0) is int # precise - assert type(res.item1) is float - assert res.item0 == f(i)[0] - assert res.item1 == f(i)[1] - -def test_pbc_getattr_conversion_with_classes(): - class base: pass - class fr1(base): pass - class fr2(base): pass - class fr3(base): pass - fr1.value = 10 - fr2.value = 5 - fr3.value = 2.5 - def pick12(i): - if i > 0: - return fr1 - else: - return fr2 - def pick23(i): - if i > 5: - return fr2 - else: - return fr3 - def f(i): - x = pick12(i) - y = pick23(i) - return x.value, y.value - for i in [0, 5, 10]: - res = interpret(f, [i]) - assert type(res.item0) is int # precise - assert type(res.item1) is float - assert res.item0 == f(i)[0] - assert res.item1 == f(i)[1] - -def test_multiple_specialized_functions(): - def myadder(x, y): # int,int->int or str,str->str - return x+y - def myfirst(x, y): # int,int->int or str,str->str - return x - def mysecond(x, y): # int,int->int or str,str->str - return y - myadder._annspecialcase_ = 'specialize:argtype(0)' - myfirst._annspecialcase_ = 'specialize:argtype(0)' - mysecond._annspecialcase_ = 'specialize:argtype(0)' - def f(i): - if i == 0: - g = myfirst - elif i == 1: - g = mysecond - else: - g = myadder - s = g("hel", "lo") - n = g(40, 2) - return len(s) * n - for i in range(3): - res = interpret(f, [i]) - assert res == f(i) - -def test_specialized_method_of_frozen(): - class space: - def __init__(self, tag): - self.tag = tag - def wrap(self, x): - if isinstance(x, int): - return self.tag + '< %d >' % x - else: - return self.tag + x - wrap._annspecialcase_ = 'specialize:argtype(1)' - space1 = space("tag1:") - space2 = space("tag2:") - def f(i): - if i == 1: - sp = space1 - else: - sp = space2 - w1 = sp.wrap('hello') - w2 = sp.wrap(42) - return w1 + w2 - res = interpret(f, [1]) - assert ''.join(res.chars) == 'tag1:hellotag1:< 42 >' - res = interpret(f, [0]) - assert ''.join(res.chars) == 'tag2:hellotag2:< 42 >' -def test_call_from_list(): - def f0(n): return n+200 - def f1(n): return n+192 - def f2(n): return n+46 - def f3(n): return n+2987 - def f4(n): return n+217 - lst = [f0, f1, f2, f3, f4] - def f(i, n): - return lst[i](n) - for i in range(5): - res = interpret(f, [i, 1000]) - assert res == f(i, 1000) +class TestLltype(BaseTestRPBC): -def test_precise_method_call_1(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - pass - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth only, using the default argument - result2 = C().meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) + ts = "lltype" + + def class_name(self, value): + return "".join(value.super.typeptr.name)[:-1] + + def read_attr(self, value, attr_name): + value = value._obj + while value is not None: + attr = getattr(value, "inst_" + attr_name, None) + if attr is None: + value = value._parentstructure() + else: + return attr + raise AttributeError() + +class TestOotype(BaseTestRPBC): + + ts = "ootype" + + def class_name(self, value): + return typeOf(value)._name.split(".")[-1] + + def read_attr(self, value, attr): + return getattr(value, "o" + attr) -def test_precise_method_call_2(): - class A(object): - def meth(self, x=5): - return x+1 - class B(A): - def meth(self, x=5): - return x+2 - class C(A): - def meth(self, x=5): - return x+3 - def f(i, n): - # call both A.meth and B.meth with an explicit argument - if i > 0: - x = A() - else: - x = B() - result1 = x.meth(n) - # now call A.meth and C.meth, using the default argument - if i > 0: - x = C() - else: - x = A() - result2 = x.meth() - return result1 * result2 - for i in [0, 1]: - res = interpret(f, [i, 1234]) - assert res == f(i, 1234) Modified: pypy/branch/njriley-trans/pypy/rpython/typesystem.py ============================================================================== --- pypy/branch/njriley-trans/pypy/rpython/typesystem.py (original) +++ pypy/branch/njriley-trans/pypy/rpython/typesystem.py Fri Mar 10 06:12:02 2006 @@ -5,10 +5,13 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.lltypesystem import lltype +from pypy.rpython import error class TypeSystem(object): __metaclass__ = extendabletype + offers_exceptiondata = True + def __getattr__(self, name): """Lazy import to avoid circular dependencies.""" def load(modname): @@ -17,7 +20,7 @@ None, None, ['__doc__']) except ImportError: return None - if name in ('rclass', 'rpbc', 'rbuiltin'): + if name in ('rclass', 'rpbc', 'rbuiltin', 'exceptiondata'): mod = load(name) if mod is not None: setattr(self, name, mod) @@ -92,6 +95,24 @@ def isCompatibleType(self, t1, t2): return lltype.isCompatibleType(t1, t2) + def generic_is(self, robj1, robj2, hop): + roriginal1 = robj1 + roriginal2 = robj2 + if robj1.lowleveltype is lltype.Void: + robj1 = robj2 + elif robj2.lowleveltype is lltype.Void: + robj2 = robj1 + if (not isinstance(robj1.lowleveltype, lltype.Ptr) or + not isinstance(robj2.lowleveltype, lltype.Ptr)): + raise TyperError('is of instances of the non-pointers: %r, %r' % ( + roriginal1, roriginal2)) + if robj1.lowleveltype != robj2.lowleveltype: + raise TyperError('is of instances of different pointer types: %r, %r' % ( + roriginal1, roriginal2)) + + v_list = hop.inputargs(robj1, robj2) + return hop.genop('ptr_eq', v_list, resulttype=lltype.Bool) + class ObjectOrientedTypeSystem(TypeSystem): name = "ootypesystem" callable_trait = (ootype.StaticMethod, ootype.static_meth) @@ -106,6 +127,23 @@ def isCompatibleType(self, t1, t2): return ootype.isCompatibleType(t1, t2) + def generic_is(self, robj1, robj2, hop): + roriginal1 = robj1 + roriginal2 = robj2 + if robj1.lowleveltype is lltype.Void: + robj1 = robj2 + elif robj2.lowleveltype is lltype.Void: + robj2 = robj1 + if (not isinstance(robj1.lowleveltype, ootype.Instance) or + not isinstance(robj2.lowleveltype, ootype.Instance)) and \ + (robj1.lowleveltype is not ootype.Class or + robj2.lowleveltype is not ootype.Class): + raise error.TyperError('is of instances of the non-instances: %r, %r' % ( + roriginal1, roriginal2)) + + v_list = hop.inputargs(robj1, robj2) + return hop.genop('oois', v_list, resulttype=lltype.Bool) + # All typesystems are singletons LowLevelTypeSystem.instance = LowLevelTypeSystem() ObjectOrientedTypeSystem.instance = ObjectOrientedTypeSystem() Modified: pypy/branch/njriley-trans/pypy/tool/isolate.py ============================================================================== --- pypy/branch/njriley-trans/pypy/tool/isolate.py (original) +++ pypy/branch/njriley-trans/pypy/tool/isolate.py Fri Mar 10 06:12:02 2006 @@ -28,6 +28,7 @@ _closed = False def __init__(self, module): + self.module = module self.slave = slaveproc.SlaveProcess(os.path.join(os.path.dirname(__file__), 'isolate_slave.py')) res = self.slave.cmd(('load', module)) Modified: pypy/branch/njriley-trans/pypy/tool/opcode.py ============================================================================== --- pypy/branch/njriley-trans/pypy/tool/opcode.py (original) +++ pypy/branch/njriley-trans/pypy/tool/opcode.py Fri Mar 10 06:12:02 2006 @@ -1,193 +1,9 @@ -# XXX this is a (hopefully temporary) copy of the 2.3 module of CPython. -# See pydis.py. +# load opcode.py as pythonopcode from our own lib +# This should handle missing local copy +def load_opcode(): + import py + opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py') + execfile(str(opcode_path), globals()) -""" -opcode module - potentially shared between dis and other modules which -operate on bytecodes (e.g. peephole optimizers). -""" - -__all__ = ["cmp_op", "hasconst", "hasname", "hasjrel", "hasjabs", - "haslocal", "hascompare", "hasfree", "opname", "opmap", - "HAVE_ARGUMENT", "EXTENDED_ARG"] - -cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is', - 'is not', 'exception match', 'BAD') - -hasconst = [] -hasname = [] -hasjrel = [] -hasjabs = [] -haslocal = [] -hascompare = [] -hasfree = [] - -opmap = {} -opname = [''] * 256 -for op in range(256): opname[op] = '<' + `op` + '>' -del op - -def def_op(name, op): - opname[op] = name - opmap[name] = op - -def name_op(name, op): - def_op(name, op) - hasname.append(op) - -def jrel_op(name, op): - def_op(name, op) - hasjrel.append(op) - -def jabs_op(name, op): - def_op(name, op) - hasjabs.append(op) - -# Instruction opcodes for compiled code - -def_op('STOP_CODE', 0) -def_op('POP_TOP', 1) -def_op('ROT_TWO', 2) -def_op('ROT_THREE', 3) -def_op('DUP_TOP', 4) -def_op('ROT_FOUR', 5) -def_op('IEXEC_THROW', 6) - -def_op('UNARY_POSITIVE', 10) -def_op('UNARY_NEGATIVE', 11) -def_op('UNARY_NOT', 12) -def_op('UNARY_CONVERT', 13) - -def_op('UNARY_INVERT', 15) - -def_op('BINARY_POWER', 19) - -def_op('BINARY_MULTIPLY', 20) -def_op('BINARY_DIVIDE', 21) -def_op('BINARY_MODULO', 22) -def_op('BINARY_ADD', 23) -def_op('BINARY_SUBTRACT', 24) -def_op('BINARY_SUBSCR', 25) -def_op('BINARY_FLOOR_DIVIDE', 26) -def_op('BINARY_TRUE_DIVIDE', 27) -def_op('INPLACE_FLOOR_DIVIDE', 28) -def_op('INPLACE_TRUE_DIVIDE', 29) - -def_op('SLICE+0', 30) -def_op('SLICE+1', 31) -def_op('SLICE+2', 32) -def_op('SLICE+3', 33) - -def_op('STORE_SLICE+0', 40) -def_op('STORE_SLICE+1', 41) -def_op('STORE_SLICE+2', 42) -def_op('STORE_SLICE+3', 43) - -def_op('DELETE_SLICE+0', 50) -def_op('DELETE_SLICE+1', 51) -def_op('DELETE_SLICE+2', 52) -def_op('DELETE_SLICE+3', 53) - -def_op('INPLACE_ADD', 55) -def_op('INPLACE_SUBTRACT', 56) -def_op('INPLACE_MULTIPLY', 57) -def_op('INPLACE_DIVIDE', 58) -def_op('INPLACE_MODULO', 59) -def_op('STORE_SUBSCR', 60) -def_op('DELETE_SUBSCR', 61) - -def_op('BINARY_LSHIFT', 62) -def_op('BINARY_RSHIFT', 63) -def_op('BINARY_AND', 64) -def_op('BINARY_XOR', 65) -def_op('BINARY_OR', 66) -def_op('INPLACE_POWER', 67) -def_op('GET_ITER', 68) - -def_op('PRINT_EXPR', 70) -def_op('PRINT_ITEM', 71) -def_op('PRINT_NEWLINE', 72) -def_op('PRINT_ITEM_TO', 73) -def_op('PRINT_NEWLINE_TO', 74) -def_op('INPLACE_LSHIFT', 75) -def_op('INPLACE_RSHIFT', 76) -def_op('INPLACE_AND', 77) -def_op('INPLACE_XOR', 78) -def_op('INPLACE_OR', 79) -def_op('BREAK_LOOP', 80) -def_op('END_IEXEC', 81) - -def_op('LOAD_LOCALS', 82) -def_op('RETURN_VALUE', 83) -def_op('IMPORT_STAR', 84) -def_op('EXEC_STMT', 85) -def_op('YIELD_VALUE', 86) - -def_op('POP_BLOCK', 87) -def_op('END_FINALLY', 88) -def_op('BUILD_CLASS', 89) - -HAVE_ARGUMENT = 90 # Opcodes from here have an argument: - -name_op('STORE_NAME', 90) # Index in name list -name_op('DELETE_NAME', 91) # "" -def_op('UNPACK_SEQUENCE', 92) # Number of tuple items -jrel_op('FOR_ITER', 93) - -name_op('STORE_ATTR', 95) # Index in name list -name_op('DELETE_ATTR', 96) # "" -name_op('STORE_GLOBAL', 97) # "" -name_op('DELETE_GLOBAL', 98) # "" -def_op('DUP_TOPX', 99) # number of items to duplicate -def_op('LOAD_CONST', 100) # Index in const list -hasconst.append(100) -name_op('LOAD_NAME', 101) # Index in name list -def_op('BUILD_TUPLE', 102) # Number of tuple items -def_op('BUILD_LIST', 103) # Number of list items -def_op('BUILD_MAP', 104) # Always zero for now -name_op('LOAD_ATTR', 105) # Index in name list -def_op('COMPARE_OP', 106) # Comparison operator -hascompare.append(106) -name_op('IMPORT_NAME', 107) # Index in name list -name_op('IMPORT_FROM', 108) # Index in name list - -jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip -jrel_op('JUMP_IF_FALSE', 111) # "" -jrel_op('JUMP_IF_TRUE', 112) # "" -jabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code - -name_op('LOAD_GLOBAL', 116) # Index in name list - -jabs_op('CONTINUE_LOOP', 119) # Target address -jrel_op('SETUP_LOOP', 120) # Distance to target address -jrel_op('SETUP_EXCEPT', 121) # "" -jrel_op('SETUP_FINALLY', 122) # "" -jrel_op('SETUP_IEXEC', 123) # "" - -def_op('LOAD_FAST', 124) # Local variable number -haslocal.append(124) -def_op('STORE_FAST', 125) # Local variable number -haslocal.append(125) -def_op('DELETE_FAST', 126) # Local variable number -haslocal.append(126) - -def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) -def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8) -def_op('MAKE_FUNCTION', 132) # Number of args with default values -def_op('BUILD_SLICE', 133) # Number of items - -def_op('MAKE_CLOSURE', 134) -def_op('LOAD_CLOSURE', 135) -hasfree.append(135) -def_op('LOAD_DEREF', 136) -hasfree.append(136) -def_op('STORE_DEREF', 137) -hasfree.append(137) - -def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8) -def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8) -def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8) - -def_op('EXTENDED_ARG', 143) -EXTENDED_ARG = 143 - -del def_op, name_op, jrel_op, jabs_op +load_opcode() +del load_opcode Modified: pypy/branch/njriley-trans/pypy/tool/option.py ============================================================================== --- pypy/branch/njriley-trans/pypy/tool/option.py (original) +++ pypy/branch/njriley-trans/pypy/tool/option.py Fri Mar 10 06:12:02 2006 @@ -16,7 +16,7 @@ # "ast" uses interpreter/pyparser & interpreter/astcompiler.py # "cpython" uses cpython parser and cpython c-level compiler usemodules = [] - version = "2.4" # "native" / "2.3" / "2.4" + version = "2.5a" # "native" / "2.3" / "2.4" / "2.5a" def run_tb_server(option, opt, value, parser): from pypy.tool import tb_server Modified: pypy/branch/njriley-trans/pypy/translator/c/database.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/database.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/database.py Fri Mar 10 06:12:02 2006 @@ -2,6 +2,7 @@ Primitive, Ptr, typeOf, RuntimeTypeInfo, \ Struct, Array, FuncType, PyObject, Void, \ ContainerType, OpaqueType +from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.llmemory import Address from pypy.rpython.memory.lladdress import NULL from pypy.translator.c.primitive import PrimitiveName, PrimitiveType @@ -107,6 +108,9 @@ node = self.containernodes[container] except KeyError: T = typeOf(container) + if isinstance(T, (lltype.Array, lltype.Struct)): + if hasattr(self.gctransformer, 'consider_constant'): + self.gctransformer.consider_constant(T, container) nodefactory = ContainerNodeFactory[T.__class__] node = nodefactory(self, T, container) self.containernodes[container] = node @@ -178,16 +182,23 @@ if i == show_i: dump() show_i += 1000 + work_to_do = False if not is_later_yet: - self.gctransformer.finish() + newgcdependencies = self.gctransformer.finish() + if newgcdependencies: + work_to_do = True + for value in newgcdependencies: + if isinstance(typeOf(value), ContainerType): + self.getcontainernode(value) + else: + self.get(value) is_later_yet = True if self.latercontainerlist: + work_to_do = True for node in self.latercontainerlist: - node.make_funcgen() + node.make_funcgens() self.containerlist.append(node) self.latercontainerlist = [] - else: - work_to_do = False self.completed = True if show_progress: dump() Modified: pypy/branch/njriley-trans/pypy/translator/c/external.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/external.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/external.py Fri Mar 10 06:12:02 2006 @@ -16,6 +16,9 @@ self.argtypenames = [db.gettype(T) for T in self.FUNCTYPE.ARGS] self.resulttypename = db.gettype(self.FUNCTYPE.RESULT) + 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))] Modified: pypy/branch/njriley-trans/pypy/translator/c/funcgen.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/funcgen.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/funcgen.py Fri Mar 10 06:12:02 2006 @@ -52,10 +52,9 @@ for op in block.operations: mix.extend(op.args) mix.append(op.result) - if hasattr(op, "cleanup"): - if op.cleanup is None: - continue - for cleanupop in op.cleanup[0] + op.cleanup[1]: + if getattr(op, "cleanup", None) is not None: + cleanup_finally, cleanup_except = op.cleanup + for cleanupop in cleanup_finally + cleanup_except: mix.extend(cleanupop.args) mix.append(cleanupop.result) for link in block.exits: @@ -83,6 +82,9 @@ self.vars = uniquemix self.lltypes = None + def name(self, cname): #virtual + return cname + def implementation_begin(self): db = self.db lltypes = {} @@ -164,7 +166,7 @@ seen[name] = True result = cdecl(self.lltypename(v), LOCALVAR % name) + ';' if self.lltypemap(v) is Void: - result = '/*%s*/' % result + continue #result = '/*%s*/' % result result_by_name.append((v._name, result)) result_by_name.sort() return [result for name, result in result_by_name] @@ -184,9 +186,13 @@ err = 'err%d_%d' % (myblocknum, i) for line in self.gen_op(op, err): yield line + # XXX hackish -- insert the finally code unless the operation + # already did cleanup = getattr(op, 'cleanup', None) - if cleanup is not None: - for subop in op.cleanup[0]: + if (cleanup is not None and + op.opname not in ("direct_call", "indirect_call")): + cleanup_finally, cleanup_except = cleanup + for subop in cleanup_finally: for line in self.gen_op(subop, "should_never_be_jumped_to2"): yield line fallthrough = False @@ -308,10 +314,11 @@ for i, op in list(enumerate(block.operations))[::-1]: if getattr(op, 'cleanup', None) is None: continue - errorcases.setdefault(op.cleanup[1], []).append(i) + cleanup_finally, cleanup_except = op.cleanup + errorcases.setdefault(cleanup_except, []).append(i) if fallthrough: - firstclean = tuple(block.operations[-1].cleanup[1]) + cleanup_finally, firstclean = block.operations[-1].cleanup first = errorcases[firstclean] del errorcases[firstclean] first.remove(len(block.operations) - 1) @@ -421,8 +428,17 @@ try: cleanup = op.cleanup except AttributeError: - raise AttributeError("(in)direct_call %r without explicit .cleanup" % op) + raise AttributeError("%r without explicit .cleanup" + % (op,)) if cleanup is not None: + # insert the 'finally' operations before the exception check + cleanup_finally, cleanup_except = op.cleanup + if cleanup_finally: + finally_lines = ['/* finally: */'] + for cleanupop in cleanup_finally: + finally_lines.extend( + self.gen_op(cleanupop, 'should_never_be_jumped_to')) + line = '%s\n%s' % (line, '\n\t'.join(finally_lines)) line = '%s\n%s' % (line, self.check_directcall_result(op, err)) return line Modified: pypy/branch/njriley-trans/pypy/translator/c/gc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/gc.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/gc.py Fri Mar 10 06:12:02 2006 @@ -192,7 +192,7 @@ is_varsize, err) if gcinfo and gcinfo.finalizer: - result += ('\nGC_REGISTER_FINALIZER(%s, %s, NULL, NULL, NULL);' + result += ('\nGC_REGISTER_FINALIZER(%s, (GC_finalization_proc)%s, NULL, NULL, NULL);' % (eresult, gcinfo.finalizer)) return result @@ -278,6 +278,22 @@ fnptr = self.db.gctransformer.frameworkgc_setup_ptr.value yield '%s();' % (self.db.get(fnptr),) + def pre_gc_code(self): + return [] + def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op, err): args = [funcgen.expr(v) for v in op.args] return '%s = %s; /* for moving GCs */' % (args[1], args[0]) + + def common_gcheader_definition(self, defnode): + return [('flags', lltype.Signed), ('typeid', lltype.Signed)] + + def common_gcheader_initdata(self, defnode): + # this more or less assumes mark-and-sweep gc + o = defnode.obj + while True: + n = o._parentstructure() + if n is None: + break + o = n + return [0, defnode.db.gctransformer.id_of_type[typeOf(o)]] Modified: pypy/branch/njriley-trans/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/genc.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/genc.py Fri Mar 10 06:12:02 2006 @@ -736,5 +736,5 @@ \t$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDEDIRS) clean: -\trm -f $(OBJECTS) +\trm -f $(OBJECTS) $(TARGET) ''' Modified: pypy/branch/njriley-trans/pypy/translator/c/node.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/node.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/node.py Fri Mar 10 06:12:02 2006 @@ -59,6 +59,9 @@ db = self.db STRUCT = self.STRUCT varlength = self.varlength + if needs_gcheader(self.STRUCT): + for fname, T in db.gcpolicy.struct_gcheader_definition(self): + self.fields.append((fname, db.gettype(T, who_asks=self))) for name in STRUCT._names: T = self.c_struct_field_type(name) if name == STRUCT._arrayfld: @@ -67,9 +70,6 @@ else: typename = db.gettype(T, who_asks=self) self.fields.append((self.c_struct_field_name(name), typename)) - if needs_gcheader(self.STRUCT): - for fname, T in db.gcpolicy.struct_gcheader_definition(self): - self.fields.insert(0, (fname, db.gettype(T, who_asks=self))) self.gcinfo # force it to be computed def computegcinfo(self): @@ -182,7 +182,8 @@ yield 'struct %s {' % self.name for fname, typename in self.gcfields: yield '\t' + cdecl(typename, fname) + ';' - yield '\tlong length;' + if not self.ARRAY._hints.get('nolength', False): + yield '\tlong length;' line = '%s;' % cdecl(self.itemtypename, 'items[%d]'% self.varlength) if self.ARRAY.OF is Void: # strange line = '/* %s */' % line @@ -216,7 +217,10 @@ def debug_offsets(self): # generate three offsets for debugging inspection - yield 'offsetof(struct %s, length)' % (self.name,) + if not self.ARRAY._hints.get('nolength', False): + yield 'offsetof(struct %s, length)' % (self.name,) + else: + yield '-1' if self.ARRAY.OF is not Void: yield 'offsetof(struct %s, items[0])' % (self.name,) yield 'offsetof(struct %s, items[1])' % (self.name,) @@ -417,7 +421,7 @@ class FuncNode(ContainerNode): nodekind = 'func' if USESLOTS: - __slots__ = """funcgen""".split() + __slots__ = """funcgens""".split() def __init__(self, db, T, obj): self.globalcontainer = True @@ -431,37 +435,38 @@ self.includes = () self.name = db.namespace.uniquename('g_' + self.basename()) if not getattr(obj, 'isgchelper', False): - self.make_funcgen() + self.make_funcgens() #self.dependencies = {} self.typename = db.gettype(T) #, who_asks=self) self.ptrname = self.name - def make_funcgen(self): - self.funcgen = select_function_code_generator(self.obj, self.db, self.name) - if self.funcgen: - argnames = self.funcgen.argnames() + 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) def basename(self): return self.obj._name def enum_dependencies(self): - if self.funcgen is None: + if not self.funcgens: return [] - return self.funcgen.allconstantvalues() + return self.funcgens[0].allconstantvalues() #Assume identical for all funcgens def forward_declaration(self): - if self.funcgen: - return ContainerNode.forward_declaration(self) - else: - return [] + for funcgen in self.funcgens: + yield '%s;' % ( + cdecl(self.implementationtypename, funcgen.name(self.name))) def implementation(self): - funcgen = self.funcgen - if funcgen is None: - return + for funcgen in self.funcgens: + for s in self.funcgen_implementation(funcgen): + yield s + + def funcgen_implementation(self, funcgen): funcgen.implementation_begin() - yield '%s {' % cdecl(self.implementationtypename, self.name) + yield '%s {' % cdecl(self.implementationtypename, funcgen.name(self.name)) # # declare the local variables # @@ -504,30 +509,36 @@ assert not USESLOTS or '__dict__' not in dir(FuncNode) -def select_function_code_generator(fnobj, db, functionname): +def select_function_code_generators(fnobj, db, functionname): if fnobj._callable in extfunc.EXTERNALS: # 'fnobj' is one of the ll_xyz() functions with the suggested_primitive # flag in pypy.rpython.module.*. The corresponding C wrappers are # written by hand in src/ll_*.h, and declared in extfunc.EXTERNALS. db.externalfuncs[fnobj._callable] = fnobj - return None + return [] elif getattr(fnobj._callable, 'suggested_primitive', False): raise ValueError, "trying to compile suggested primitive %r" % ( fnobj._callable,) elif hasattr(fnobj, 'graph'): cpython_exc = getattr(fnobj, 'exception_policy', None) == "CPython" if hasattr(db, 'stacklessdata') and not db.use_stackless_transformation: - from pypy.translator.c.stackless import SlpFunctionCodeGenerator - gencls = SlpFunctionCodeGenerator + split_slp_function = False + if split_slp_function: + from pypy.translator.c.stackless import SlpSaveOnlyFunctionCodeGenerator, \ + SlpResumeFunctionCodeGenerator + return [SlpSaveOnlyFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname), + SlpResumeFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] + else: + from pypy.translator.c.stackless import SlpFunctionCodeGenerator + return [SlpFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] else: - gencls = FunctionCodeGenerator - return gencls(fnobj.graph, db, cpython_exc, functionname) + return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] elif getattr(fnobj, 'external', None) == 'C': # deprecated case if getattr(fnobj, 'includes', None): - return None # assume no wrapper needed + return [] # assume no wrapper needed else: - return CExternalFunctionCodeGenerator(fnobj, db) + return [CExternalFunctionCodeGenerator(fnobj, db)] else: raise ValueError, "don't know how to generate code for %r" % (fnobj,) Modified: pypy/branch/njriley-trans/pypy/translator/c/primitive.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/primitive.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/primitive.py Fri Mar 10 06:12:02 2006 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem.lltype import * from pypy.rpython.lltypesystem.llmemory import Address, fakeaddress, \ AddressOffset, ItemOffset, ArrayItemsOffset, FieldOffset, \ - CompositeOffset + CompositeOffset, ArrayLengthOffset from pypy.rpython.memory.gc import GCHeaderOffset from pypy.rpython.memory.lladdress import NULL @@ -24,6 +24,9 @@ elif isinstance(value, ArrayItemsOffset): return 'offsetof(%s, items)'%( db.gettype(value.TYPE).replace('@', '')) + elif isinstance(value, ArrayLengthOffset): + return 'offsetof(%s, length)'%( + db.gettype(value.TYPE).replace('@', '')) elif isinstance(value, CompositeOffset): return '%s + %s' % (name_signed(value.first, db), name_signed(value.second, db)) elif type(value) == AddressOffset: @@ -83,10 +86,22 @@ if value is NULL: return 'NULL' assert isinstance(value, fakeaddress) - if value.ob is None: - return 'NULL' + if value.offset is None: + if value.ob is None: + return 'NULL' + else: + if isinstance(typeOf(value.ob), ContainerType): + return db.getcontainernode(value.ob).ptrname + else: + return db.get(value.ob) else: - return db.get(value.ob) + assert value.offset is not None + if isinstance(typeOf(value.ob), ContainerType): + base = db.getcontainernode(value.ob).ptrname + else: + base = db.get(value.ob) + + return '(void*)(((char*)(%s)) + (%s))'%(base, db.get(value.offset)) PrimitiveName = { Signed: name_signed, Modified: pypy/branch/njriley-trans/pypy/translator/c/src/address.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/address.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/address.h Fri Mar 10 06:12:02 2006 @@ -17,7 +17,7 @@ #define OP_ADR_GE(x,y,r,err) r = ((x) >= (y)) #define OP_RAW_MALLOC(size,r,err) \ - r = (void*) malloc(size); \ + r = (void*) calloc(1, size); \ if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ #ifdef MS_WINDOWS Modified: pypy/branch/njriley-trans/pypy/translator/c/src/g_prerequisite.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/g_prerequisite.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/g_prerequisite.h Fri Mar 10 06:12:02 2006 @@ -11,3 +11,5 @@ #include "thread.h" /* needs to be included early to define the struct RPyOpaque_ThreadLock */ + +#include Modified: pypy/branch/njriley-trans/pypy/translator/c/src/support.h ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/src/support.h (original) +++ pypy/branch/njriley-trans/pypy/translator/c/src/support.h Fri Mar 10 06:12:02 2006 @@ -33,7 +33,9 @@ PyObject * gencfunc_descr_get(PyObject *func, PyObject *obj, PyObject *type); PyObject* PyList_Pack(int n, ...); PyObject* PyDict_Pack(int n, ...); +#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ PyObject* PyTuple_Pack(int n, ...); +#endif #if PY_VERSION_HEX >= 0x02030000 /* 2.3 */ # define PyObject_GetItem1 PyObject_GetItem # define PyObject_SetItem1 PyObject_SetItem Modified: pypy/branch/njriley-trans/pypy/translator/c/stackless.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/stackless.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/stackless.py Fri Mar 10 06:12:02 2006 @@ -211,6 +211,7 @@ class SlpFunctionCodeGenerator(FunctionCodeGenerator): + needs_resume = True def cfunction_body(self): # lists filled by check_directcall_result() from super.cfunction_body() @@ -219,13 +220,16 @@ body = list(super(SlpFunctionCodeGenerator, self).cfunction_body()) # if self.savelines: # header (if we need to resume) - yield 'if (slp_frame_stack_top) goto resume;' + if self.needs_resume: + yield 'if (slp_frame_stack_top) goto resume;' for line in body: # regular body yield line if self.savelines: yield '' for line in self.savelines: # save-state-away lines yield line + if not self.needs_resume: + return yield '' yield 'resume:' # resume-state blocks yield '{' @@ -247,7 +251,7 @@ argtypes = [T for T in argtypes if T is not lltype.Void] rettype = signature_type(self.lltypemap(self.graph.getreturnvar())) FUNC = lltype.FuncType(argtypes, rettype) - slpdata.registerunwindable(self.functionname, FUNC, + slpdata.registerunwindable(self.name(self.functionname), FUNC, resume_points = len(self.resumeblocks)) del self.savelines @@ -346,6 +350,17 @@ return line +class SlpSaveOnlyFunctionCodeGenerator(SlpFunctionCodeGenerator): + needs_resume = False + + +class SlpResumeFunctionCodeGenerator(SlpFunctionCodeGenerator): + needs_resume = True + + def name(self, cname): + return cname + '_SlpResume' + + def signature_type(T): """Return T unless it's a pointer type, in which case we return a general basic pointer type. Modified: pypy/branch/njriley-trans/pypy/translator/c/symboltable.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/symboltable.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/symboltable.py Fri Mar 10 06:12:02 2006 @@ -142,13 +142,18 @@ ARRAY = self._TYPE.TO if isinstance(ARRAY, Array): length_offset = self._nth_offset(0) + if length_offset == -1: + raise TypeError, "array has no stored length: %r" % (ARRAY,) return self._read(Signed, length_offset) raise TypeError, "not an array: %r" % (ARRAY,) def __getitem__(self, index): ARRAY = self._TYPE.TO if isinstance(ARRAY, Array): - if not (0 <= index < len(self)): + length_offset = self._nth_offset(0) + if length_offset == -1: + pass # just assume the access is within bounds + elif not (0 <= index < len(self)): raise IndexError("array index out of bounds") item0_offset = self._nth_offset(1) item1_offset = self._nth_offset(2) Modified: pypy/branch/njriley-trans/pypy/translator/c/test/test_boehm.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/test/test_boehm.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/test/test_boehm.py Fri Mar 10 06:12:02 2006 @@ -2,6 +2,7 @@ from pypy.translator.translator import TranslationContext from pypy.translator.tool.cbuild import skip_missing_compiler, check_boehm_presence from pypy.translator.c.genc import CExtModuleBuilder +from pypy import conftest def setup_module(mod): if not check_boehm_presence(): @@ -32,6 +33,8 @@ def compile(): cbuilder = CExtModuleBuilder(t, func, gcpolicy=self.gcpolicy) c_source_filename = cbuilder.generate_source() + if conftest.option.view: + t.view() cbuilder.compile() mod = cbuilder.isolated_import() self._cleanups.append(cbuilder.cleanup) # schedule cleanup after test Modified: pypy/branch/njriley-trans/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/test/test_genc.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/test/test_genc.py Fri Mar 10 06:12:02 2006 @@ -4,6 +4,7 @@ from pypy.translator.translator import TranslationContext from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c.genc import gen_source +from pypy.translator.c.gc import NoneGcPolicy from pypy.objspace.flow.model import Constant, Variable, SpaceOperation from pypy.objspace.flow.model import Block, Link, FunctionGraph from pypy.tool.udir import udir @@ -28,18 +29,19 @@ include_dirs = [os.path.dirname(autopath.this_dir)]) return m -def compile(fn, argtypes, view=False): +def compile(fn, argtypes, view=False, gcpolicy=None, backendopt=True): t = TranslationContext() a = t.buildannotator() a.build_types(fn, argtypes) t.buildrtyper().specialize() - if view or conftest.option.view: - t.view() - backend_optimizations(t) - db = LowLevelDatabase(t) + if backendopt: + backend_optimizations(t) + db = LowLevelDatabase(t, gcpolicy=gcpolicy) entrypoint = db.get(pyobjectptr(fn)) db.complete() module = compile_db(db) + if view or conftest.option.view: + t.view() compiled_fn = getattr(module, entrypoint) def checking_fn(*args, **kwds): res = compiled_fn(*args, **kwds) @@ -296,3 +298,91 @@ f1 = compile(f, []) assert f1() == 1 + +# ____________________________________________________________ +# test for the 'cleanup' attribute of SpaceOperations +class CleanupState(object): + pass +cleanup_state = CleanupState() +cleanup_state.current = 1 +def cleanup_g(n): + cleanup_state.saved = cleanup_state.current + try: + return 10 // n + except ZeroDivisionError: + raise +def cleanup_h(): + cleanup_state.current += 1 +def cleanup_f(n): + cleanup_g(n) + cleanup_h() # the test hacks the graph to put this h() in the + # cleanup clause of the previous direct_call(g) + return cleanup_state.saved * 100 + cleanup_state.current + +def test_cleanup_finally(): + class DummyGCTransformer(NoneGcPolicy.transformerclass): + def transform_graph(self, graph): + super(DummyGCTransformer, self).transform_graph(graph) + if graph is self.translator.graphs[0]: + operations = graph.startblock.operations + op_call_g = operations[0] + op_call_h = operations.pop(1) + assert op_call_g.opname == "direct_call" + assert op_call_h.opname == "direct_call" + assert op_call_g.cleanup == ((), ()) + assert op_call_h.cleanup == ((), ()) + cleanup_finally = (op_call_h,) + cleanup_except = () + op_call_g.cleanup = cleanup_finally, cleanup_except + op_call_h.cleanup = None + + class DummyGcPolicy(NoneGcPolicy): + transformerclass = DummyGCTransformer + + f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) + # state.current == 1 + res = f1(1) + assert res == 102 + # state.current == 2 + res = f1(1) + assert res == 203 + # state.current == 3 + py.test.raises(ZeroDivisionError, f1, 0) + # state.current == 4 + res = f1(1) + assert res == 405 + # state.current == 5 + +def test_cleanup_except(): + class DummyGCTransformer(NoneGcPolicy.transformerclass): + def transform_graph(self, graph): + super(DummyGCTransformer, self).transform_graph(graph) + if graph is self.translator.graphs[0]: + operations = graph.startblock.operations + op_call_g = operations[0] + op_call_h = operations.pop(1) + assert op_call_g.opname == "direct_call" + assert op_call_h.opname == "direct_call" + assert op_call_g.cleanup == ((), ()) + assert op_call_h.cleanup == ((), ()) + cleanup_finally = () + cleanup_except = (op_call_h,) + op_call_g.cleanup = cleanup_finally, cleanup_except + op_call_h.cleanup = None + + class DummyGcPolicy(NoneGcPolicy): + transformerclass = DummyGCTransformer + + f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) + # state.current == 1 + res = f1(1) + assert res == 101 + # state.current == 1 + res = f1(1) + assert res == 101 + # state.current == 1 + py.test.raises(ZeroDivisionError, f1, 0) + # state.current == 2 + res = f1(1) + assert res == 202 + # state.current == 2 Modified: pypy/branch/njriley-trans/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/test/test_newgc.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/test/test_newgc.py Fri Mar 10 06:12:02 2006 @@ -193,7 +193,7 @@ class TestUsingFramework(AbstractTestClass): from pypy.translator.c.gc import FrameworkGcPolicy as gcpolicy - def test_nongcing_gc(self): + def test_framework_simple(self): def g(x): return x + 1 class A(object): @@ -201,7 +201,86 @@ def f(): a = A() a.b = g(1) + # this should trigger a couple of collections + # XXX make sure it triggers at least one somehow! + for i in range(100000): + [A()] * 1000 return a.b fn = self.getcompiled(f) res = fn() assert res == 2 + + def test_framework_varsized(self): + S = lltype.GcStruct("S", ('x', lltype.Signed)) + T = lltype.GcStruct("T", ('y', lltype.Signed), + ('s', lltype.Ptr(S))) + ARRAY_Ts = lltype.GcArray(lltype.Ptr(T)) + + def f(): + r = 0 + for i in range(30): + a = lltype.malloc(ARRAY_Ts, i) + for j in range(i): + a[j] = lltype.malloc(T) + a[j].y = i + a[j].s = lltype.malloc(S) + a[j].s.x = 2*i + r += a[j].y + a[j].s.x + a[j].s = lltype.malloc(S) + a[j].s.x = 3*i + r -= a[j].s.x + for j in range(i): + r += a[j].y + return r + fn = self.getcompiled(f) + res = fn() + assert res == f() + + + def test_framework_using_lists(self): + class A(object): + pass + N = 1000 + def f(): + static_list = [] + for i in range(N): + a = A() + a.x = i + static_list.append(a) + r = 0 + for a in static_list: + r += a.x + return r + fn = self.getcompiled(f) + res = fn() + assert res == N*(N - 1)/2 + + def test_framework_static_roots(self): + class A(object): + def __init__(self, y): + self.y = y + a = A(0) + a.x = None + def f(): + a.x = A(42) + for i in range(1000000): + A(i) + return a.x.y + fn = self.getcompiled(f) + res = fn() + assert res == 42 + + def test_framework_nongc_static_root(self): + S = lltype.GcStruct("S", ('x', lltype.Signed)) + T = lltype.Struct("T", ('p', lltype.Ptr(S))) + t = lltype.malloc(T, immortal=True) + def f(): + t.p = lltype.malloc(S) + t.p.x = 43 + for i in range(1000000): + s = lltype.malloc(S) + s.x = i + return t.p.x + fn = self.getcompiled(f) + res = fn() + assert res == 43 Modified: pypy/branch/njriley-trans/pypy/translator/c/test/test_symbolic.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/test/test_symbolic.py (original) +++ pypy/branch/njriley-trans/pypy/translator/c/test/test_symbolic.py Fri Mar 10 06:12:02 2006 @@ -25,6 +25,16 @@ res = fn() assert res == 12 +def test_sizeof_array_with_no_length(): + A = lltype.Array(lltype.Signed, hints={'nolength': True}) + arraysize = llmemory.sizeof(A, 10) + signedsize = llmemory.sizeof(lltype.Signed) + def f(): + return arraysize-signedsize*10 + fn, t = getcompiled(f, []) + res = fn() + assert res == 0 + def test_itemoffsetof(): ARRAY = lltype.GcArray(lltype.Signed) itemoffsets = [llmemory.itemoffsetof(ARRAY, i) for i in range(5)] Modified: pypy/branch/njriley-trans/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/branch/njriley-trans/pypy/translator/c/winproj/extension/extension.vcproj Fri Mar 10 06:12:02 2006 @@ -33,6 +33,7 @@ Name="VCCustomBuildTool"/> @@ -78,7 +80,8 @@ Name="VCCustomBuildTool"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\common_header.h"> + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\testing_1.c"> Modified: pypy/branch/njriley-trans/pypy/translator/c/winproj/standalone/standalone.vcproj ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/c/winproj/standalone/standalone.vcproj (original) +++ pypy/branch/njriley-trans/pypy/translator/c/winproj/standalone/standalone.vcproj Fri Mar 10 06:12:02 2006 @@ -208,181 +208,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-257\testing_1\testing_1.c"> Modified: pypy/branch/njriley-trans/pypy/translator/driver.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/driver.py (original) +++ pypy/branch/njriley-trans/pypy/translator/driver.py Fri Mar 10 06:12:02 2006 @@ -188,6 +188,15 @@ # task_rtype = taskdef(task_rtype, ['annotate'], "RTyping") + def task_ootype(self): + # Maybe type_system should simply be an option used in task_rtype + opt = self.options + rtyper = self.translator.buildrtyper(type_system="ootype") + rtyper.specialize(dont_simplify_again=True, + crash_on_first_typeerror=not opt.insist) + # + task_ootype = taskdef(task_ootype, ['annotate'], "ootyping") + def task_backendopt(self): from pypy.translator.backendopt.all import backend_optimizations opt = self.options @@ -211,6 +220,9 @@ if opt.gc == 'none': from pypy.translator.c import gc gcpolicy = gc.NoneGcPolicy + if opt.gc == 'framework': + from pypy.translator.c import gc + gcpolicy = gc.FrameworkGcPolicy if standalone: from pypy.translator.c.genc import CStandaloneBuilder as CBuilder Modified: pypy/branch/njriley-trans/pypy/translator/geninterplevel.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/geninterplevel.py (original) +++ pypy/branch/njriley-trans/pypy/translator/geninterplevel.py Fri Mar 10 06:12:02 2006 @@ -203,7 +203,7 @@ self.builtin_ids = dict( [ (id(value), bltinstub(key)) for key, value in __builtin__.__dict__.items() - if callable(value) and type(value) not in [type(Exception), type] ] ) + if callable(value) and type(value) not in [types.ClassType, type] ] ) self.space = FlowObjSpace() # for introspection @@ -748,7 +748,7 @@ return 'space.w_%s' % cls.__name__ if not isinstance(cls, type): - assert type(cls) is type(Exception) + assert type(cls) is types.ClassType # do *not* change metaclass, but leave the # decision to what PyPy thinks is correct. # metaclass = 'space.w_classobj' @@ -824,7 +824,7 @@ str: 'space.w_str', float: 'space.w_float', slice: 'space.w_slice', - type(Exception()): (eval_helper, 'InstanceType', 'types.InstanceType'), + types.InstanceType: (eval_helper, 'InstanceType', 'types.InstanceType'), type: 'space.w_type', complex: (eval_helper, 'complex', 'types.ComplexType'), unicode:'space.w_unicode', Modified: pypy/branch/njriley-trans/pypy/translator/gensupp.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/gensupp.py (original) +++ pypy/branch/njriley-trans/pypy/translator/gensupp.py Fri Mar 10 06:12:02 2006 @@ -85,11 +85,12 @@ # while always keeping all globals visible. class NameManager(object): - def __init__(self, global_prefix=''): + def __init__(self, global_prefix='', number_sep='_'): self.seennames = {} self.scope = 0 self.scopelist = [] self.global_prefix = global_prefix + self.number_sep = number_sep def make_reserved_names(self, txt): """add names to list of known names. If one exists already, @@ -113,7 +114,7 @@ self.seennames[basename] = n+1 if with_number is None: with_number = basename in ('v', 'w_') - fmt = '%s_%d' + fmt = '%%s%s%%d' % self.number_sep if with_number and not basename[-1].isdigit(): fmt = '%s%d' if n != 0 or with_number: Modified: pypy/branch/njriley-trans/pypy/translator/goal/translate.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/goal/translate.py (original) +++ pypy/branch/njriley-trans/pypy/translator/goal/translate.py Fri Mar 10 06:12:02 2006 @@ -48,7 +48,7 @@ '1_backend': [OPT(('-b', '--backend'), "Backend", ['c', 'llvm'])], - '2_gc': [OPT(('--gc',), "Garbage collector", ['boehm', 'ref', 'none'])], + '2_gc': [OPT(('--gc',), "Garbage collector", ['boehm', 'ref', 'framework', 'none'])], '3_stackless': [OPT(('--stackless',), "Stackless code generation", True)], '4_tsc': [OPT(('--tsc',), "(x86, PowerPC, Alpha) Timestamp counter profile", True)], '5_merge_if_blocks': [OPT(('--no-if-blocks-merge',), "Do not merge if ... elif ... chains and use a switch statement for them.", False)], Modified: pypy/branch/njriley-trans/pypy/translator/interactive.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/interactive.py (original) +++ pypy/branch/njriley-trans/pypy/translator/interactive.py Fri Mar 10 06:12:02 2006 @@ -48,6 +48,7 @@ GOAL_USES_OPTS = { 'annotate': ['debug'], 'rtype': ['insist'], + 'ootype': [], 'backendopt': ['merge_if_blocks'], 'database_c': ['gc', 'stackless'], 'source_llvm': ['gc', 'stackless'], @@ -81,9 +82,9 @@ else: # check consistency if argtypes is not None and argtypes != self.ann_argtypes: - raise Exception("incosistent argtype supplied") + raise Exception("inconsistent argtype supplied") if policy is not None and policy != self.ann_policy: - raise Exception("incosistent annotation polish supplied") + raise Exception("inconsistent annotation polish supplied") def update_options(self, argtypes, kwds): if argtypes or kwds.get('policy'): @@ -91,7 +92,7 @@ for optname, value in kwds.iteritems(): if optname in self.frozen_options: if getattr(self.driver.options, optname) != value: - raise Exception("incosistent option supplied: %s" % optname) + raise Exception("inconsistent option supplied: %s" % optname) else: setattr(self.driver.options, optname, value) self.frozen_options[optname] = True @@ -120,6 +121,10 @@ self.update_options(argtypes, kwds) return self.driver.rtype() + def ootype(self, argtypes=None, **kwds): + self.update_options(argtypes, kwds) + return self.driver.ootype() + # backend depedent def backendopt(self, argtypes=None, **kwds): Modified: pypy/branch/njriley-trans/pypy/translator/llvm/codewriter.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/codewriter.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/codewriter.py Fri Mar 10 06:12:02 2006 @@ -135,7 +135,16 @@ "%(fromvar)s to %(targettype)s" % locals()) def getelementptr(self, targetvar, type, typevar, indices, getptr=True): - # XXX comment getptr + # getelementptr gives you back a value for the last thing indexed + + # what is getptr? + # --------------- + # All global variables in LLVM are pointers, and pointers must also be + # dereferenced with the getelementptr instruction (hence the int 0) + + # not only that, but if we need to look into something (ie a struct) + # then we must get the initial pointer to ourself + if getptr: indices = [(self.word_repr, 0)] + list(indices) res = "%(targetvar)s = getelementptr %(type)s %(typevar)s, " % locals() Modified: pypy/branch/njriley-trans/pypy/translator/llvm/database.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/database.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/database.py Fri Mar 10 06:12:02 2006 @@ -5,7 +5,7 @@ from pypy.translator.llvm.funcnode import FuncNode, FuncTypeNode from pypy.translator.llvm.extfuncnode import ExternalFuncNode from pypy.translator.llvm.structnode import StructNode, StructVarsizeNode, \ - StructTypeNode, StructVarsizeTypeNode + StructTypeNode, StructVarsizeTypeNode, getindexhelper from pypy.translator.llvm.arraynode import ArrayNode, StrArrayNode, \ VoidArrayNode, ArrayTypeNode, VoidArrayTypeNode from pypy.translator.llvm.opaquenode import OpaqueNode, ExtOpaqueNode, \ @@ -366,10 +366,39 @@ # XXXXX things are happening in the gc world... # assert value == NULL repr = 'null' + elif isinstance(value, llmemory.AddressOffset): + return self.offset_str(value) else: repr = str(value) return repr + def offset_str(self, value): + + #XXX Need to understand and doc this better + + if isinstance(value, llmemory.FieldOffset): + pos = getindexhelper(value.fldname, value.TYPE) + return "cast(%s* getelementptr(%s* null, int 0, uint %s) to int)" % ( + self.repr_type(getattr(value.TYPE, value.fldname)), + self.repr_type(value.TYPE), + pos) + + elif isinstance(value, llmemory.ItemOffset): + return "cast(%s* getelementptr(%s* null, int %s) to int)" % ( + self.repr_type(value.TYPE), self.repr_type(value.TYPE), value.repeat) + + elif isinstance(value, llmemory.ArrayItemsOffset): + return "cast(%s* getelementptr(%s* null, int 0, uint 1) to int)" % ( + self.repr_type(value.TYPE.OF), self.repr_type(value.TYPE)) + + elif isinstance(value, llmemory.CompositeOffset): + return "cast(%s* getelementptr(%s* null, int 0, uint 1, int %s) to int)" % ( + self.repr_type(value.second.TYPE), + self.repr_type(value.first.TYPE), + value.second.repeat) + else: + raise Exception("unsupported offset") + def get_machine_word(self): return self.primitives[lltype.Signed] Modified: pypy/branch/njriley-trans/pypy/translator/llvm/demo/bpnn.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/demo/bpnn.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/demo/bpnn.py Fri Mar 10 06:12:02 2006 @@ -221,8 +221,6 @@ return 0 #_________________________________________________________ - -from pypy.translator.llvm.genllvm import compile_function if __name__ == "__main__": from pypy.translator.llvm.demo.run import run Modified: pypy/branch/njriley-trans/pypy/translator/llvm/demo/run.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/demo/run.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/demo/run.py Fri Mar 10 06:12:02 2006 @@ -25,8 +25,9 @@ backend_optimizations(t) cbuilder = CStandaloneBuilder(t, entry_point, gcpolicy=BoehmGcPolicy) cbuilder.generate_source() - cbuilder.compile() - os.system("XXX") + exe_path = cbuilder.compile() + print exe_path + os.system(exe_path) def l(name): s_list_of_strings = SomeList(ListDef(None, SomeString())) Modified: pypy/branch/njriley-trans/pypy/translator/llvm/externs2ll.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/externs2ll.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/externs2ll.py Fri Mar 10 06:12:02 2006 @@ -104,7 +104,7 @@ def setup_externs(db): rtyper = db.translator.rtyper - from pypy.translator.c.extfunc import predeclare_all + from pypy.translator.llvm.extfunchelper import predeclare_all # hacks to make predeclare_all work # XXX Rationalise this Modified: pypy/branch/njriley-trans/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/genllvm.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/genllvm.py Fri Mar 10 06:12:02 2006 @@ -1,6 +1,8 @@ import time -from pypy.translator.llvm import build_llvm_module +from pypy.tool import isolate + +from pypy.translator.llvm import buildllvm from pypy.translator.llvm.database import Database from pypy.translator.llvm.pyxwrapper import write_pyx_wrapper from pypy.rpython.rmodel import inputconst @@ -17,6 +19,7 @@ from pypy.translator.llvm.exception import ExceptionPolicy from pypy.translator.llvm.log import log from pypy import conftest +from pypy.translator.llvm.buildllvm import llvm_is_on_path class GenLLVM(object): @@ -237,9 +240,9 @@ if exe_name is not None: assert self.standalone assert not return_fn - return build_llvm_module.make_module_from_llvm(self, self.filename, - optimize=optimize, - exe_name=exe_name) + return buildllvm.make_module_from_llvm(self, self.filename, + optimize=optimize, + exe_name=exe_name) else: assert not self.standalone @@ -248,15 +251,20 @@ basename = self.filename.purebasename + '_wrapper' + postfix + '.pyx' pyxfile = self.filename.new(basename = basename) write_pyx_wrapper(self, pyxfile) - res = build_llvm_module.make_module_from_llvm(self, self.filename, - pyxfile=pyxfile, - optimize=optimize) - wrap_fun = getattr(res, 'pypy_' + self.entry_func_name + "_wrapper") + info = buildllvm.make_module_from_llvm(self, self.filename, + pyxfile=pyxfile, + optimize=optimize) + + mod, wrap_fun = self.isolate_module(*info) if return_fn: return wrap_fun + return mod, wrap_fun - return res, wrap_fun - + def isolate_module(self, modname, dirpath): + ext_module = isolate.Isolate((dirpath, modname)) + wrap_fun = getattr(ext_module, 'pypy_' + self.entry_func_name + "_wrapper") + return ext_module, wrap_fun + def _checkpoint(self, msg=None): if not self.logging: return @@ -298,6 +306,8 @@ return gen.compile_llvm_source(**kwds) def genllvm_compile(function, annotation, view=False, optimize=True, **kwds): + assert llvm_is_on_path() + from pypy.translator.translator import TranslationContext from pypy.translator.backendopt.all import backend_optimizations t = TranslationContext() @@ -316,7 +326,3 @@ if view or conftest.option.view: t.view() return genllvm(t, function, optimize=optimize, **kwds) - -def compile_function(function, annotation, **kwds): - """ Helper - which get the compiled module from CPython. """ - return compile_module(function, annotation, return_fn=True, **kwds) Modified: pypy/branch/njriley-trans/pypy/translator/llvm/opwriter.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/opwriter.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/opwriter.py Fri Mar 10 06:12:02 2006 @@ -1,6 +1,8 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype from pypy.translator.llvm.log import log +from pypy.translator.llvm.structnode import getindexhelper + log = log.opwriter class OpRepr(object): @@ -313,21 +315,11 @@ else: raise NotImplementedError - def _getindexhelper(self, name, struct): - assert name in list(struct._names) - - fieldnames = struct._names_without_voids() - try: - index = fieldnames.index(name) - except ValueError: - index = -1 - return index - def getfield(self, opr): op = opr.op if opr.rettype != "void": - index = self._getindexhelper(op.args[1].value, - op.args[0].concretetype.TO) + index = getindexhelper(op.args[1].value, + op.args[0].concretetype.TO) assert index != -1 tmpvar = self._tmp() self.codewriter.getelementptr(tmpvar, opr.argtypes[0], @@ -337,8 +329,8 @@ self._skipped(opr) def getsubstruct(self, opr): - index = self._getindexhelper(opr.op.args[1].value, - opr.op.args[0].concretetype.TO) + index = getindexhelper(opr.op.args[1].value, + opr.op.args[0].concretetype.TO) assert opr.rettype != "void" self.codewriter.getelementptr(opr.retref, opr.argtypes[0], opr.argrefs[0], [("uint", index)]) @@ -347,8 +339,8 @@ op = opr.op if opr.argtypes[2] != "void": tmpvar = self._tmp() - index = self._getindexhelper(op.args[1].value, - op.args[0].concretetype.TO) + index = getindexhelper(op.args[1].value, + op.args[0].concretetype.TO) self.codewriter.getelementptr(tmpvar, opr.argtypes[0], opr.argrefs[0], [("uint", index)]) self.codewriter.store(opr.argtypes[2], opr.argrefs[2], tmpvar) Modified: pypy/branch/njriley-trans/pypy/translator/llvm/structnode.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/structnode.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/structnode.py Fri Mar 10 06:12:02 2006 @@ -2,6 +2,16 @@ from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode from pypy.rpython.lltypesystem import lltype +def getindexhelper(name, struct): + assert name in list(struct._names) + + fieldnames = struct._names_without_voids() + try: + index = fieldnames.index(name) + except ValueError: + index = -1 + return index + log = log.structnode class StructTypeNode(LLVMNode): Modified: pypy/branch/njriley-trans/pypy/translator/llvm/test/runtest.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/llvm/test/runtest.py (original) +++ pypy/branch/njriley-trans/pypy/translator/llvm/test/runtest.py Fri Mar 10 06:12:02 2006 @@ -1,24 +1,9 @@ import py from pypy.translator.llvm.genllvm import genllvm_compile - +from pypy.translator.llvm.buildllvm import llvm_is_on_path, llvm_version optimize_tests = False MINIMUM_LLVM_VERSION = 1.6 -def llvm_is_on_path(): - try: - py.path.local.sysfind("llvm-as") - py.path.local.sysfind("llvm-gcc") - except py.error.ENOENT: - return False - return True - -def llvm_version(): - import os - v = os.popen('llvm-as -version 2>&1').readline() - v = ''.join([c for c in v if c.isdigit()]) - v = int(v) / 10.0 - return v - def llvm_test(): if not llvm_is_on_path(): py.test.skip("llvm not found") Modified: pypy/branch/njriley-trans/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/squeak/gensqueak.py (original) +++ pypy/branch/njriley-trans/pypy/translator/squeak/gensqueak.py Fri Mar 10 06:12:02 2006 @@ -1,254 +1,71 @@ -import sys +import datetime, sys from pypy.objspace.flow.model import traverse from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Constant, Variable, Block from pypy.objspace.flow.model import last_exception, checkgraph +from pypy.translator.gensupp import NameManager from pypy.translator.unsimplify import remove_direct_loops from pypy.translator.simplify import simplify_graph +from pypy.rpython.ootypesystem.ootype import Instance, ROOT from pypy import conftest +try: + set +except NameError: + from sets import Set as set -selectormap = { - 'setitem:with:': 'at:put:', - 'getitem:': 'at:', - 'new': 'new', - 'runtimenew': 'new', - 'classof': 'class', - 'sameAs': 'yourself', - 'intAdd:': '+', -} - -def camel_case(str): - words = str.split('_') - for i in range(1, len(words)): - words[i] = words[i].capitalize() - return ''.join(words) - -def arg_names(graph): - #XXX need to handle more args, see - # http://docs.python.org/ref/types.html#l2h-139 - names, vararg, kwarg = graph.signature - assert vararg is None - assert kwarg is None - return names - -def selector(name, args): - s = name - if args: - s += '_' - for arg in args: - s += arg + ':' - return camel_case(s) - -def signature(sel, args): - if (':' in sel): - parts = [] - names = sel.split(':') -# assert len(names) == len(args) - while args: - parts.append(names.pop(0) + ': ' + args.pop(0)) - return ' '.join(parts) - elif not sel[0].isalnum(): -# assert len(args) == 1 - return "%s %s" %(sel, args[0]) - else: -# assert len(args) == 0 - return sel - - -class LoopFinder: - def __init__(self, startblock): - self.loops = {} - self.parents = {startblock: startblock} - self.temps = {} - self.seen = [] - self.visit_Block(startblock) - def visit_Block(self, block, switches=[]): - #self.temps.has_key() - self.seen.append(block) - if block.exitswitch: - switches.append(block) - self.parents[block] = block - for link in block.exits: - self.visit_Link(link, switches) - def visit_Link(self, link, switches): - if link.target in switches: - self.loops[link.target] = True - if not link.target in self.seen: - self.parents[link.target] = self.parents[link.prevblock] - self.visit_Block(link.target, switches) class GenSqueak: + sqnames = { + Constant(None).key: 'nil', + Constant(False).key: 'false', + Constant(True).key: 'true', + } + def __init__(self, sqdir, translator, modname=None): self.sqdir = sqdir self.translator = translator self.modname = (modname or translator.graphs[0].name) - self.sqnames = { - Constant(None).key: 'nil', - Constant(False).key: 'false', - Constant(True).key: 'true', - } - self.seennames = {} - self.pendinggraphs = [] - self.pendingclasses = [] - self.pendingmethods = [] - self.classes = [] - self.methods = [] - - t = self.translator - graph = t.graphs[0] - simplify_graph(graph) - remove_direct_loops(t, graph) - checkgraph(graph) + + self.name_manager = NameManager(number_sep="") + self.unique_name_mapping = {} + self.pending_nodes = [] + self.generated_nodes = set() if conftest.option.view: self.translator.view() - self.nameof(graph) #add to pending - file = self.sqdir.join('%s.st' % graph.name).open('w') + graph = self.translator.graphs[0] + self.pending_nodes.append(FunctionNode(self, graph)) + self.filename = '%s.st' % graph.name + file = self.sqdir.join(self.filename).open('w') self.gen_source(file) file.close() - def gen_source(self, file): - while self.pendinggraphs or self.pendingclasses or self.pendingmethods: - while self.pendinggraphs: - graph = self.pendinggraphs.pop() - self.gen_sqfunction(graph, file) - while self.pendingclasses: - inst = self.pendingclasses.pop() - self.gen_sqclass(inst, file) - while self.pendingmethods: - (inst, meth) = self.pendingmethods.pop() - self.gen_sqmethod(inst, meth, file) - - def gen_sqclass(self, inst, f): - self.classes.append(inst) - print >> f, """%s subclass: #%s - instanceVariableNames: '%s' - classVariableNames: '' - poolDictionaries: '' - category: 'PyPy-Test'! - """ % ( - self.nameof_Instance(inst._superclass), - self.nameof_Instance(inst), - ' '.join(inst._fields.iterkeys())) - - def gen_sqmethod(self, inst, meth, f): - if (inst, meth) in self.methods: - return - self.methods.append((inst, meth)) - print >> f, "!%s methodsFor: 'methods' stamp: 'pypy 1/1/2000 00:00'!" % ( - self.nameof_Instance(inst)) - print >> f, "%s" % meth - print >> f, ' "XXX methods not generated yet"' - print >> f, "! !" - print >> f - - - def gen_sqfunction(self, graph, f): - - def expr(v): - if isinstance(v, Variable): - return camel_case(v.name) - elif isinstance(v, Constant): - return self.nameof(v.value) - else: - raise TypeError, "expr(%r)" % (v,) - - def oper(op): - args = [expr(arg) for arg in op.args] - if op.opname == "oosend": - name = op.args[0].value - receiver = args[1] - args = args[2:] - self.note_meth(op.args[1].concretetype, name) - elif op.opname == "oogetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - elif op.opname == "oosetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - else: - name = op.opname - receiver = args[0] - args = args[1:] - argnames = ['with'] * len(args) - if argnames: - argnames[0] = '' - sel = selector(name, argnames) - if op.opname != "oosend": - sel = selectormap.get(sel, sel) - return "%s := %s %s." % (expr(op.result), receiver, signature(sel, args)) - - def render_return(args): - if len(args) == 2: - # exception - exc_cls = expr(args[0]) - exc_val = expr(args[1]) - yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) - else: - # regular return block - retval = expr(args[0]) - yield "^%s" % retval - - def render_link(link): - block = link.target - if link.args: - for i in range(len(link.args)): - yield '%s := %s.' % (expr(block.inputargs[i]), expr(link.args[i])) - for line in render_block(block): - yield line - - def render_block(block): - if loops.has_key(block): - if not loops[block]: - yield '"skip1"' - return - yield "[" - for op in block.operations: - yield "%s" % oper(op) - if len(block.exits) == 0: - for line in render_return(block.inputargs): - yield line + while self.pending_nodes: + node = self.pending_nodes.pop() + self.gen_node(node, file) + + def gen_node(self, node, f): + for dep in node.dependencies(): + if dep not in self.generated_nodes: + self.pending_nodes.append(node) + self.schedule_node(dep) return - elif block.exitswitch is None: - # single-exit block - assert len(block.exits) == 1 - for line in render_link(block.exits[0]): - yield line - else: - #exitswitch - if loops.has_key(block): - if loops[block]: - loops[block] = False - yield "%s] whileTrue: [" % expr(block.exitswitch) - for line in render_link(block.exits[True]): - yield " %s" % line - yield "]." - for line in render_link(block.exits[False]): - yield "%s" % line - else: - yield "%s ifTrue: [" % expr(block.exitswitch) - for line in render_link(block.exits[True]): - yield " %s" % line - yield "] ifFalse: [" - for line in render_link(block.exits[False]): - yield " %s" % line - yield "]" - - start = graph.startblock - args = [expr(arg) for arg in start.inputargs] - print >> f, '%s' % signature(self.nameof(graph), args) - - loops = LoopFinder(start).loops - - for line in render_block(start): - print >> f, ' %s' % line - print >> f + self.generated_nodes.add(node) + for line in node.render(): + print >> f, line + print >> f, "" + + def schedule_node(self, node): + if node not in self.generated_nodes: + if node in self.pending_nodes: + # We move the node to the front so we can enforce + # the generation of dependencies. + self.pending_nodes.remove(node) + self.pending_nodes.append(node) def nameof(self, obj): key = Constant(obj).key @@ -274,64 +91,344 @@ def nameof_str(self, s): return "'s'" - def nameof_FunctionGraph(self, graph): - #XXX this should actually be a StaticMeth - name = self.unique_name(graph.name.split('.')[-1]) - args = arg_names(graph) - sel = selector(name, args) - self.pendinggraphs.append(graph) - return sel - - #def nameof_function(self, func): - # #XXX this should actually be a StaticMeth - # printable_name = '(%s:%d) %s' % ( - # func.func_globals.get('__name__', '?'), - # func.func_code.co_firstlineno, - # func.__name__) - # if self.translator.frozen: - # if func not in self.translator.flowgraphs: - # print "NOT GENERATING", printable_name - # return self.skipped_function(func) - # else: - # if (func.func_doc and - # func.func_doc.lstrip().startswith('NOT_RPYTHON')): - # print "skipped", printable_name - # return self.skipped_function(func) - # name = self.unique_name(func.__name__) - # args = arg_names(func) - # sel = selector(name, args) - # self.pendingfunctions.append(func) - # return sel - - def nameof_Instance(self, inst): - if inst is None: - #empty superclass + def nameof_Instance(self, INSTANCE): + if INSTANCE is None: return "Object" - self.note_Instance(inst) - return "Py%s" % inst._name.capitalize() + self.schedule_node(ClassNode(self, INSTANCE)) + class_name = INSTANCE._name.split(".")[-1] + squeak_class_name = self.unique_name(INSTANCE, class_name) + return "Py%s" % squeak_class_name + + def nameof__instance(self, inst): + return self.nameof_Instance(inst._TYPE) + + def nameof__callable(self, callable): + return self.nameof_function(callable.graph.func) + + def nameof_function(self, function): + squeak_func_name = self.unique_name(function, function.__name__) + return squeak_func_name + + def unique_name(self, key, basename): + if self.unique_name_mapping.has_key(key): + unique = self.unique_name_mapping[key] + else: + camel_basename = camel_case(basename) + unique = self.name_manager.uniquename(camel_basename) + self.unique_name_mapping[key] = unique + return unique + + +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) + +class Selector: + + def __init__(self, function_name, arg_count): + self.parts = [camel_case(function_name)] + self.arg_count = arg_count + self.infix = False + if not self.parts[0].isalnum(): + # Binary infix selector, e.g. "+" + assert arg_count == 1 + self.infix = True + if arg_count > 1: + self.parts += ["with"] * (arg_count - 1) + + def __str__(self): + if self.arg_count == 0 or self.infix: + return self.parts[0] + else: + return "%s:%s" % (self.parts[0], + "".join([p + ":" for p in self.parts[1:]])) + + def symbol(self): + return str(self) + + def signature(self, arg_names): + assert len(arg_names) == self.arg_count + if self.arg_count == 0: + return self.parts[0] + elif self.infix: + return "%s %s" % (self.parts[0], arg_names[0]) + else: + return " ".join(["%s: %s" % (p, a) + for (p, a) in zip(self.parts, arg_names)]) + + +class CodeNode: + + def __hash__(self): + return hash(self.hash_key) + + def __eq__(self, other): + return isinstance(other, CodeNode) \ + and self.hash_key == other.hash_key + + # XXX need other comparison methods? + + def render_fileout_header(self, class_name, category): + return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( + class_name, category, + datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) + +class ClassNode(CodeNode): + + def __init__(self, gen, INSTANCE): + self.gen = gen + self.INSTANCE = INSTANCE + self.hash_key = INSTANCE + + def dependencies(self): + if self.INSTANCE._superclass is not None: # not root + return [ClassNode(self.gen, self.INSTANCE._superclass)] + else: + return [] + + def render(self): + yield "%s subclass: #%s" % ( + self.gen.nameof_Instance(self.INSTANCE._superclass), + self.gen.nameof_Instance(self.INSTANCE)) + yield " instanceVariableNames: '%s'" % \ + ' '.join(self.INSTANCE._fields.iterkeys()) + yield " classVariableNames: ''" + yield " poolDictionaries: ''" + yield " category: 'PyPy-Test'!" + +class LoopFinder: + + def __init__(self, startblock): + self.loops = {} + self.parents = {startblock: startblock} + self.temps = {} + self.seen = [] + self.visit_Block(startblock) + + def visit_Block(self, block, switches=[]): + #self.temps.has_key() + self.seen.append(block) + if block.exitswitch: + switches.append(block) + self.parents[block] = block + for link in block.exits: + self.visit_Link(link, switches) + + def visit_Link(self, link, switches): + if link.target in switches: + self.loops[link.target] = True + if not link.target in self.seen: + self.parents[link.target] = self.parents[link.prevblock] + self.visit_Block(link.target, switches) + +class CallableNode(CodeNode): - def note_Instance(self, inst): - if inst not in self.classes: - if inst not in self.pendingclasses: - self.pendingclasses.append(inst) - - def note_meth(self, inst, meth): - bm = (inst, meth) - if bm not in self.methods: - if bm not in self.pendingmethods: - self.pendingmethods.append(bm) - - def unique_name(self, basename): - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if n == 0: - return basename + selectormap = { + #'setitem:with:': 'at:put:', + #'getitem:': 'at:', + 'new': Selector('new', 0), + 'runtimenew': Selector('new', 0), + 'classof': Selector('class', 0), + 'sameAs': Selector('yourself', 0), + 'intAdd:': Selector('+', 1), + } + + def render_body(self, startblock): + self.loops = LoopFinder(startblock).loops + args = self.arguments(startblock) + sel = Selector(self.name, len(args)) + yield sel.signature([self.expr(v) for v in args]) + + # XXX should declare local variables here + for line in self.render_block(startblock): + yield " %s" % line + yield '! !' + + def expr(self, v): + if isinstance(v, Variable): + return camel_case(v.name) + elif isinstance(v, Constant): + return self.gen.nameof(v.value) + else: + raise TypeError, "expr(%r)" % (v,) + + def oper(self, op): + args = [self.expr(arg) for arg in op.args] + if op.opname == "oosend": + name = op.args[0].value + receiver = args[1] + if hasattr(self, "self") and op.args[1] == self.self: + receiver = "self" + args = args[2:] + self.gen.schedule_node( + MethodNode(self.gen, op.args[1].concretetype, name)) + elif op.opname == "oogetfield": + receiver = args[0] + name = op.args[1].value + args = args[2:] + if hasattr(self, "self") and op.args[0] == self.self: + # Could also directly substitute op.result with name + # everywhere for optimization. + return "%s := %s." % (self.expr(op.result), name) + else: + self.gen.schedule_node( + GetterNode(self.gen, op.args[0].concretetype, name)) + elif op.opname == "oosetfield": + receiver = args[0] + name = op.args[1].value + args = args[2:] + if hasattr(self, "self") and op.args[0] == self.self: + # Note that the receiver variable is never used + return "%s := %s." % (name, args[0]) + else: + self.gen.schedule_node( + SetterNode(self.gen, op.args[0].concretetype, name)) + elif op.opname == "direct_call": + # XXX not sure if static methods of a specific class should + # be treated differently. + receiver = "PyFunctions" + name = args[0] + args = args[1:] + self.gen.schedule_node( + FunctionNode(self.gen, op.args[0].value.graph)) + else: + name = op.opname + receiver = args[0] + args = args[1:] + sel = Selector(name, len(args)) + if op.opname != "oosend": + sel = self.selectormap.get(sel.symbol(), sel) + return "%s := %s %s." \ + % (self.expr(op.result), receiver, sel.signature(args)) + + def render_return(self, args): + if len(args) == 2: + # exception + exc_cls = self.expr(args[0]) + exc_val = self.expr(args[1]) + yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) + else: + # regular return block + retval = self.expr(args[0]) + yield "^%s" % retval + + def render_link(self, link): + block = link.target + if link.args: + for i in range(len(link.args)): + yield '%s := %s.' % \ + (self.expr(block.inputargs[i]), self.expr(link.args[i])) + for line in self.render_block(block): + yield line + + def render_block(self, block): + if self.loops.has_key(block): + if not self.loops[block]: + yield '"skip1"' + return + yield "[" + for op in block.operations: + yield "%s" % self.oper(op) + if len(block.exits) == 0: + for line in self.render_return(block.inputargs): + yield line + return + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for line in self.render_link(block.exits[0]): + yield line else: - return self.unique_name('%s_%d' % (basename, n)) + #exitswitch + if self.loops.has_key(block): + if self.loops[block]: + self.loops[block] = False + yield "%s] whileTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "]." + for line in self.render_link(block.exits[False]): + yield "%s" % line + else: + yield "%s ifTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "] ifFalse: [" + for line in self.render_link(block.exits[False]): + yield " %s" % line + yield "]" + +class MethodNode(CallableNode): + + def __init__(self, gen, INSTANCE, method_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.name = method_name + self.hash_key = (INSTANCE, method_name) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def arguments(self, startblock): + # Omit the explicit self + return startblock.inputargs[1:] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof(self.INSTANCE), "methods") + graph = self.INSTANCE._methods[self.name].graph + self.self = graph.startblock.inputargs[0] + for line in self.render_body(graph.startblock): + yield line + +class FunctionNode(CallableNode): + + FUNCTIONS = Instance("Functions", ROOT) + def __init__(self, gen, graph): + self.gen = gen + self.graph = graph + self.name = gen.nameof(graph.func) + self.hash_key = graph + + def dependencies(self): + return [ClassNode(self.gen, self.FUNCTIONS)] + + def arguments(self, startblock): + return startblock.inputargs + + def render(self): + yield self.render_fileout_header("PyFunctions class", "functions") + for line in self.render_body(self.graph.startblock): + yield line + +class AccessorNode(CodeNode): + + def __init__(self, gen, INSTANCE, field_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.field_name = field_name + self.hash_key = (INSTANCE, field_name, self.__class__) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + +class SetterNode(AccessorNode): + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield "%s: value" % self.field_name + yield " %s := value" % self.field_name + yield "! !" + +class GetterNode(AccessorNode): + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield self.field_name + yield " ^%s" % self.field_name + yield "! !" - def skipped_function(self, func): - # debugging only! Generates a placeholder for missing functions - # that raises an exception when called. - name = self.unique_name(camel_case('skipped_' + func.__name__)) - return name Modified: pypy/branch/njriley-trans/pypy/translator/squeak/test/test_oo.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/squeak/test/test_oo.py (original) +++ pypy/branch/njriley-trans/pypy/translator/squeak/test/test_oo.py Fri Mar 10 06:12:02 2006 @@ -16,7 +16,7 @@ GenSqueak(udir, t) -C = Instance("test", None, {'a': (Signed, 3)}) +C = Instance("test", ROOT, {'a': (Signed, 3)}) M = Meth([Signed], Signed) def m_(self, b): return self.a+b @@ -28,12 +28,6 @@ return new(C) build_sqfunc(f_new) -def test_simple_meth(): - def f_meth(): - c = new(C) - return c.m(5) - build_sqfunc(f_meth) - def test_simple_fields(): def f_fields(): c = new(C) Modified: pypy/branch/njriley-trans/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/branch/njriley-trans/pypy/translator/squeak/test/test_squeaktrans.py Fri Mar 10 06:12:02 2006 @@ -1,36 +1,192 @@ +import os +import py from pypy.tool.udir import udir from pypy.translator.test import snippet -from pypy.translator.squeak.gensqueak import GenSqueak +from pypy.translator.squeak.gensqueak import GenSqueak, Selector, camel_case from pypy.translator.translator import TranslationContext +from pypy import conftest -def looping(i = (int), j = (int)): +def looping(i, j): while i > 0: i -= 1 while j > 0: j -= 1 -class TestSqueakTrans: +def build_sqfunc(func, args=[]): + try: func = func.im_func + except AttributeError: pass + t = TranslationContext() + t.buildannotator().build_types(func, args) + t.buildrtyper(type_system="ootype").specialize() + if conftest.option.view: + t.viewcg() + return GenSqueak(udir, t) - def build_sqfunc(self, func): - try: func = func.im_func - except AttributeError: pass - t = TranslationContext() - graph = t.buildflowgraph(func) - t._prebuilt_graphs[func] = graph - self.gen = GenSqueak(udir, t) +class TestSqueakTrans: def test_simple_func(self): - self.build_sqfunc(snippet.simple_func) + build_sqfunc(snippet.simple_func, [int]) def test_if_then_else(self): - self.build_sqfunc(snippet.if_then_else) - - def test_two_plus_two(self): - self.build_sqfunc(snippet.two_plus_two) + build_sqfunc(snippet.if_then_else, [bool, int, int]) def test_my_gcd(self): - self.build_sqfunc(snippet.my_gcd) + build_sqfunc(snippet.my_gcd, [int, int]) def test_looping(self): - self.build_sqfunc(looping) + build_sqfunc(looping, [int, int]) + + +# For now use pipes to communicate with squeak. This is very flaky +# and only works for posix systems. At some later point we'll +# probably need a socket based solution for this. +startup_script = """ +| stdout src selector result arguments arg i | +src := Smalltalk getSystemAttribute: 3. +FileStream fileIn: src. +selector := (Smalltalk getSystemAttribute: 4) asSymbol. +arguments := OrderedCollection new. +i := 4. +[(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil] + whileTrue: [arguments add: arg asInteger]. + +result := (PyFunctions perform: selector withArguments: arguments asArray). +stdout := StandardFileStream fileNamed: '/dev/stdout'. +stdout nextPutAll: result asString. +Smalltalk snapshot: false andQuit: true. +""" + +class TestGenSqueak: + + def setup_class(self): + self.startup_st = udir.join("startup.st") + f = self.startup_st.open("w") + f.write(startup_script) + f.close() + + def run_on_squeak(self, function, *args): + # NB: only integers arguments are supported currently + try: + import posix + except ImportError: + py.test.skip("Squeak tests only work on Unix right now.") + try: + py.path.local.sysfind("squeak") + except py.error.ENOENT: + py.test.skip("Squeak is not on your path.") + if os.getenv("SQUEAK_IMAGE") is None: + py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " + "variable to point to an image.") + arg_types = [type(arg) for arg in args] + gen_squeak = build_sqfunc(function, arg_types) + cmd = 'squeak -headless -- %s %s "%s" %s' \ + % (self.startup_st, udir.join(gen_squeak.filename), + Selector(function.__name__, len(args)).symbol(), + " ".join(['"%s"' % a for a in args])) + squeak_process = os.popen(cmd) + result = squeak_process.read() + assert squeak_process.close() is None # exit status was 0 + return result + + def test_theanswer(self): + def theanswer(): + return 42 + assert self.run_on_squeak(theanswer) == "42" + + def test_simplemethod(self): + class A: + def m(self): + return 42 + def simplemethod(): + return A().m() + assert self.run_on_squeak(simplemethod) == "42" + + def test_argfunction(self): + def function(i, j=2): + return i + j + assert self.run_on_squeak(function, 1, 3) == "4" + + def test_argmethod(self): + class A: + def m(self, i, j, h=2): + return i + j + h + def simplemethod(i): + return A().m(i, j=3) + assert self.run_on_squeak(simplemethod, 1) == "6" + + def test_nameclash_classes(self): + from pypy.translator.squeak.test.support import A as A2 + class A: + def m(self, i): return 2 + i + def f(): + return A().m(0) + A2().m(0) + assert self.run_on_squeak(f) == "3" + + def test_nameclash_classes_mean(self): + class A: + def m(self, i): return 1 + i + A2 = A + class A: + def m(self, i): return 2 + i + def f(): + return A().m(0) + A2().m(0) + assert self.run_on_squeak(f) == "3" + + def test_nameclash_camel_case(self): + class ASomething: + def m(self, i): return 1 + i + class A_Something: + def m(self, i): return 2 + i + def f(): + x = ASomething().m(0) + A_Something().m(0) + return x + ASomething().m(0) + A_Something().m(0) + assert self.run_on_squeak(f) == "6" + + def test_nameclash_functions(self): + from pypy.translator.squeak.test.support import f as f2 + def f(i): + return i + 2 + def g(): + return f(0) + f2(0) + assert self.run_on_squeak(g) == "3" + + def test_direct_call(self): + def h(i): + return g(i) + 1 # another call to g to try to trap GenSqueak + def g(i): + return i + 1 + def f(i): + return h(i) + g(i) + assert self.run_on_squeak(f, 1) == "5" + + def test_getfield_setfield(self): + class A: + def set(self, i): + self.i = i + def inc(self): + self.i = self.i + 1 + def f(i): + a = A() + a.set(i) + i = a.i + a.i = 3 + a.inc() + return i + a.i + assert self.run_on_squeak(f, 2) == "6" + + +class TestSelector: + + def test_selector(self): + assert Selector("bla_bla", 0).symbol() == "blaBla" + assert Selector("bla", 1).symbol() == "bla:" + assert Selector("bla_bla_bla", 3).symbol() == "blaBlaBla:with:with:" + assert Selector("+", 1).symbol() == "+" + + def test_signature(self): + assert Selector("bla", 0).signature([]) == "bla" + assert Selector("bla", 1).signature(["v"]) == "bla: v" + assert Selector("bla", 2).signature(["v0", "v1"]) == "bla: v0 with: v1" + assert Selector("+", 1).signature(["v"]) == "+ v" + Modified: pypy/branch/njriley-trans/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/njriley-trans/pypy/translator/tool/cbuild.py Fri Mar 10 06:12:02 2006 @@ -94,7 +94,8 @@ extra_compile_args = [] # ensure correct math on windows if sys.platform == 'win32': - extra_compile_args.append('/Op') + extra_compile_args.append('/Op') # get extra precision + extra_compile_args.append('/PDB:laber') # create debug info if get_default_compiler() == 'unix': old_version = False try: @@ -273,6 +274,8 @@ self.libraries.append('pthread') self.compile_extra += ['-O2', '-pthread'] self.link_extra += ['-pthread'] + if sys.platform == 'win32': + self.link_extra += ['/DEBUG'] # generate .pdb file if sys.platform == 'darwin': if '/sw/include' not in self.include_dirs: self.include_dirs.append('/sw/include') Modified: pypy/branch/njriley-trans/pypy/translator/tool/graphpage.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/tool/graphpage.py (original) +++ pypy/branch/njriley-trans/pypy/translator/tool/graphpage.py Fri Mar 10 06:12:02 2006 @@ -169,6 +169,8 @@ #info = self.links.get(var.name, var.name) #info = '(%s) %s' % (var.concretetype, info) info = str(var.concretetype) + if info == 'Void': # gray out Void variables + info = info, (160,160,160) self.links[var.name] = info for graph in graphs: Modified: pypy/branch/njriley-trans/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/tool/make_dot.py (original) +++ pypy/branch/njriley-trans/pypy/translator/tool/make_dot.py Fri Mar 10 06:12:02 2006 @@ -143,10 +143,10 @@ iargs = " ".join(map(repr, block.inputargs)) if block.exc_handler: - eh = 'EH' + eh = ' (EH)' else: eh = '' - data = "%s%s(%s %s)\\ninputargs: %s\\n\\n" % (name, block.at(), block.__class__.__name__, eh, iargs) + data = "%s%s%s\\ninputargs: %s\\n\\n" % (name, block.at(), eh, iargs) if block.operations and self.func: maxoffs = max([op.offset for op in block.operations]) if maxoffs >= 0: Modified: pypy/branch/njriley-trans/pypy/translator/translator.py ============================================================================== --- pypy/branch/njriley-trans/pypy/translator/translator.py (original) +++ pypy/branch/njriley-trans/pypy/translator/translator.py Fri Mar 10 06:12:02 2006 @@ -2,7 +2,7 @@ The Translator is a glue class putting together the various pieces of the translation-related code. It can be used for interactive testing of the -translator; see pypy/bin/translator.py. +translator; see pypy/bin/translatorshell.py. """ import autopath, os, sys, types, copy From ac at codespeak.net Fri Mar 10 09:35:48 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Fri, 10 Mar 2006 09:35:48 +0100 (CET) Subject: [pypy-svn] r24202 - in pypy/dist/pypy/module/__builtin__: . test Message-ID: <20060310083548.8CD14100BC@code0.codespeak.net> Author: ac Date: Fri Mar 10 09:35:47 2006 New Revision: 24202 Modified: pypy/dist/pypy/module/__builtin__/app_functional.py pypy/dist/pypy/module/__builtin__/test/test_functional.py Log: apply() takes 1-3 arguments. Modified: pypy/dist/pypy/module/__builtin__/app_functional.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/app_functional.py (original) +++ pypy/dist/pypy/module/__builtin__/app_functional.py Fri Mar 10 09:35:47 2006 @@ -13,7 +13,7 @@ # ____________________________________________________________ -def apply(function, args, kwds={}): +def apply(function, args=(), kwds={}): """call a function (or other callable object) and return its result""" return function(*args, **kwds) Modified: pypy/dist/pypy/module/__builtin__/test/test_functional.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_functional.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_functional.py Fri Mar 10 09:35:47 2006 @@ -132,6 +132,15 @@ assert list(reversed(list(reversed("hello")))) == ['h','e','l','l','o'] raises(TypeError, reversed, reversed("hello")) +class AppTestApply: + def test_apply(self): + def f(*args, **kw): + return args, kw + args = (1,3) + kw = {'a': 1, 'b': 4} + assert apply(f) == ((), {}) + assert apply(f, args) == (args, {}) + assert apply(f, args, kw) == (args, kw) class AppTestAllAny: """ From ac at codespeak.net Fri Mar 10 10:23:11 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Fri, 10 Mar 2006 10:23:11 +0100 (CET) Subject: [pypy-svn] r24205 - in pypy/dist/pypy/interpreter: astcompiler test Message-ID: <20060310092311.3846C10083@code0.codespeak.net> Author: ac Date: Fri Mar 10 10:23:10 2006 New Revision: 24205 Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py pypy/dist/pypy/interpreter/test/test_nestedscope.py Log: A GenExpr is a kind of function. Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/symbols.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/symbols.py Fri Mar 10 10:23:10 2006 @@ -188,7 +188,7 @@ GenExprScopeCounter = Counter(1) -class GenExprScope(Scope): +class GenExprScope(FunctionScope): def __init__(self, module, klass=None): i = GenExprScopeCounter.next() @@ -292,15 +292,13 @@ def visitGenExpr(self, node ): parent = self.cur_scope() scope = GenExprScope(self.module, self.klass); - if parent.nested or isinstance(parent, FunctionScope) \ - or isinstance(parent, GenExprScope): + if parent.nested or isinstance(parent, FunctionScope): scope.nested = 1 node.scope = scope self.push_scope(scope) node.code.accept(self) self.pop_scope() - self.handle_free_vars(scope, parent) def visitGenExprInner(self, node ): Modified: pypy/dist/pypy/interpreter/test/test_nestedscope.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_nestedscope.py (original) +++ pypy/dist/pypy/interpreter/test/test_nestedscope.py Fri Mar 10 10:23:10 2006 @@ -57,3 +57,6 @@ keys = outer_locals.keys() keys.sort() assert keys == ['h', 'x'] + + def test_lambda_in_genexpr(self): + assert eval('map(apply, (lambda: t for t in range(10)))') == range(10) From mwh at codespeak.net Fri Mar 10 11:34:52 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 10 Mar 2006 11:34:52 +0100 (CET) Subject: [pypy-svn] r24206 - in pypy/dist/pypy: rpython/memory translator/c/test Message-ID: <20060310103452.52474100B0@code0.codespeak.net> Author: mwh Date: Fri Mar 10 11:34:51 2006 New Revision: 24206 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: argh, arrays of Void! this means using a different check for fixedsizedness (set offset to length to -1 in the fixed size case) and inserting some special cases in get_type_id. a few more special cases in primitive.py would probably mean a few less in gctransform.py but, well. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Fri Mar 10 11:34:51 2006 @@ -666,7 +666,7 @@ TYPE_INFO_TABLE = lltype.Array(TYPE_INFO) def q_is_varsize(typeid): - return gcdata.type_info_table[typeid].varitemsize != 0 + return gcdata.type_info_table[typeid].ofstolength != -1 def q_offsets_to_gc_pointers(typeid): return gcdata.type_info_table[typeid].ofstoptrs @@ -816,21 +816,29 @@ info["ofstoptrs"] = self.offsets2table(offsets) if not TYPE._is_varsize(): info["fixedsize"] = llmemory.sizeof(TYPE) + info["ofstolength"] = -1 else: info["fixedsize"] = llmemory.sizeof(TYPE, 0) if isinstance(TYPE, lltype.Struct): ARRAY = TYPE._flds[TYPE._arrayfld] ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld) info["ofstolength"] = ofs1 - info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) + if ARRAY.OF != lltype.Void: + info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) + else: + info["fixedsize"] = ofs1 + llmemory.sizeof(lltype.Signed) else: ARRAY = TYPE info["ofstolength"] = llmemory.ArrayLengthOffset(ARRAY) - info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0) + if ARRAY.OF != lltype.Void: + info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0) + else: + info["fixedsize"] = llmemory.ArrayLengthOffset(ARRAY) + llmemory.sizeof(lltype.Signed) assert isinstance(ARRAY, lltype.Array) - offsets = offsets_to_gc_pointers(ARRAY.OF) - info["varofstoptrs"] = self.offsets2table(offsets) - info["varitemsize"] = llmemory.sizeof(ARRAY.OF) + if ARRAY.OF != lltype.Void: + offsets = offsets_to_gc_pointers(ARRAY.OF) + info["varofstoptrs"] = self.offsets2table(offsets) + info["varitemsize"] = llmemory.sizeof(ARRAY.OF) return type_id def consider_constant(self, TYPE, value): Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Fri Mar 10 11:34:51 2006 @@ -284,3 +284,14 @@ fn = self.getcompiled(f) res = fn() assert res == 43 + + def test_framework_void_array(self): + A = lltype.GcArray(lltype.Void) + a = lltype.malloc(A, 44) + def f(): + return len(a) + fn = self.getcompiled(f) + res = fn() + assert res == 44 + + From nico at codespeak.net Fri Mar 10 11:50:11 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Fri, 10 Mar 2006 11:50:11 +0100 (CET) Subject: [pypy-svn] r24208 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060310105011.5FB28100BF@code0.codespeak.net> Author: nico Date: Fri Mar 10 11:50:09 2006 New Revision: 24208 Added: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.txt Log: sprint report Added: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.txt Fri Mar 10 11:50:09 2006 @@ -0,0 +1,118 @@ +Sprint Report Louvain-La-Neuve 6-10/3/2006 +========================================== + +Achievements +------------ + +The main achievements of the sprint are : + + * wrapper of GECODE constraint-solving library + + * workshop about functionnalities of the PyPy/Python and Oz languages + + * microthreads and dataflow variables in Logic ObjectSpace + + * draft of a standard mechanism to express search problems in Python + +Sprint participants +------------------- + +Ludovic Aubry, Aur?lien Camp?as, Nicolas Chauvat, Alexandre Fayolle, +Anders Lehmann, Gr?goire Dooms, Samuele Pedroni, Carl Friedrich Bolz, +Rapha?l Collet. + +Workshop participants +--------------------- + +Sprinters + Roel Wuyts, Peter Van Roy, Kevin Glynn, Luis Quesada, +Boris Mejias, Jean-No?l Monette, Pierre Schaus + +Before workshop +--------------- + +Monday and Tuesday where spent sharing information about what had been +implemented, discussing what could be implemented and looking at +existing implementations. This is what the planning was like: + +* identify parts of the current logic module that can be usefully implemented + in RPython + +* take a look at existing logic programming software and think about integration + (pychinko_ and Rete_ algorithm or CWM_ for forward-chaining, GECODE_ + library for constraint-solving, tableau, pylog_ for + backward-chaining, Python Cookbook recipes, etc.) + +* existing Python syntax/new syntax: look at and update existing document in pypy's svn + +* consistency for multi-paradigm programming languages (especially + Python). Oz_ has consistent semantics and offers many different + programming paradigms (object, functionnal, constraint, distributed, + secure, dataflow, etc.) + +References that we looked at are: + +* the Rete_ algorithm, an efficient algorithm_ for rule-based systems + +* CWM_, a rule-based system written in Python by Tim Berners-Lee + +* pychinko_, a Python implementation of RETE + +* pylog_, an implementation of prolog in python that compiles prolog + source code to Python functions + +* a Python cookbook recipe_ that lets one add arbitrary infix binary operators + +* a simple Prolog implementation using continuations_ to implement backtracking search + +* `linear programming`_ with nice syntactic sugar via operator overloading + +* candygram_, erlang style message-based communication and concurrency in Python + +* discussing extending python with `futures/promises`_ + +* two_ python recipes_ that analyse and transform the bytecode of a + function to interpret it as a set of facts and rules + +.. _GECODE: http://www.gecode.org/ +.. _Rete: http://en.wikipedia.org/wiki/Rete +.. _algorithm: http://drools.org/Rete +.. _CWM: http://infomesh.net/2001/cwm/ +.. _pychinko: http://www.mindswap.org/~katz/pychinko/ +.. _pylog: http://christophe.delord.free.fr/en/pylog/ +.. _recipe: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 +.. _continuations: http://www.ps.uni-sb.de/~duchier/python/continuations.html +.. _`linear programming`: http://www.jeannot.org/~js/code/index.en.html +.. _candygram: http://candygram.sourceforge.net/ +.. _`futures/promises`: http://lists.logilab.org/pipermail/python-logic/2005-August/000112.html +.. _two: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/360698 +.. _recipes: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303057 +.. _Oz: http://www.mozart-oz.org/ + +Workshop +-------- + +* presentation of pypy architecture + +* presentation of current implementation of a constraint store in python + +* presentation of soul/smalltalk language symbiosis + +* presentation of dataflow paradigm and basic mechanisms + +After the workshop +------------------ + +Samuele and Carl implemented a logic object space with microthreads +and logic variables. See dist/pypy/objspace/logic.py + +Nicolas, Rapha?l and Aur?lien discussed a design for a generic +computation space similar to Oz's object space that could run searches +expressed as a constraint problem or as a rule-set. + +Ludovic, Alexandre and Gr?goire wrapped the GECODE library. See +dist/pypy/lib/logic/gecode_wrapper + +Alexandre and Anders used PyPy to compile the constraints before +running the search and gained a nice speedup. + + From nico at codespeak.net Fri Mar 10 11:53:24 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Fri, 10 Mar 2006 11:53:24 +0100 (CET) Subject: [pypy-svn] r24209 - pypy/dist/pypy/doc Message-ID: <20060310105324.3412E100BC@code0.codespeak.net> Author: nico Date: Fri Mar 10 11:53:22 2006 New Revision: 24209 Modified: pypy/dist/pypy/doc/events.txt pypy/dist/pypy/doc/news.txt Log: sprint almost done Modified: pypy/dist/pypy/doc/events.txt ============================================================================== --- pypy/dist/pypy/doc/events.txt (original) +++ pypy/dist/pypy/doc/events.txt Fri Mar 10 11:53:22 2006 @@ -7,18 +7,6 @@ .. _`over there`: webcal://pypycal.sabi.net///calendars/PyPy.ics -Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) -======================================================================== - -*March 6th - March 10th 2006.* Developers focusing on adding logic programming -to PyPy will meet with -the team that developed the Oz programming language and the Mozart -interpreter. - -Read more in `the announcement`_. - -.. _`the announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/louvain-la-neuve-2006/sprint-announcement.html - Talks at Python UK/ACCU Conference (United Kingdom) =================================================================== Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Fri Mar 10 11:53:22 2006 @@ -7,6 +7,19 @@ .. _Python: http://www.python.org/doc/current/ref/ref.html .. _`more...`: http://codespeak.net/pypy/dist/pypy/doc/architecture.html#mission-statement + +Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) +======================================================================== + +*March 6th - March 10th 2006.* PyPy developers focusing on adding +logic programming to PyPy will met with the team that developed the Oz +programming language and the Mozart interpreter. + +Read the report_ and the original announcement_. + +.. _report: http://codespeak.net/pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.html +.. _announcement: http://codespeak.net/pypy/extradoc/sprintinfo/louvain-la-neuve-2006/sprint-announcement.html + PyCon Sprint 2006 (Dallas, Texas, USA) ================================================================== From nik at codespeak.net Fri Mar 10 12:01:59 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 10 Mar 2006 12:01:59 +0100 (CET) Subject: [pypy-svn] r24211 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060310110159.A88D3100C5@code0.codespeak.net> Author: nik Date: Fri Mar 10 12:01:53 2006 New Revision: 24211 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: tried to make a test about class variables pass (skipped for now), but then got annoyed at the way dispatching on llops is done and refactored that instead. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Fri Mar 10 12:01:53 2006 @@ -232,6 +232,7 @@ 'classof': Selector('class', 0), 'sameAs': Selector('yourself', 0), 'intAdd:': Selector('+', 1), + 'intEq:': Selector('=', 1), } def render_body(self, startblock): @@ -254,53 +255,70 @@ raise TypeError, "expr(%r)" % (v,) def oper(self, op): - args = [self.expr(arg) for arg in op.args] - if op.opname == "oosend": - name = op.args[0].value - receiver = args[1] - if hasattr(self, "self") and op.args[1] == self.self: - receiver = "self" - args = args[2:] - self.gen.schedule_node( - MethodNode(self.gen, op.args[1].concretetype, name)) - elif op.opname == "oogetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - if hasattr(self, "self") and op.args[0] == self.self: - # Could also directly substitute op.result with name - # everywhere for optimization. - return "%s := %s." % (self.expr(op.result), name) - else: - self.gen.schedule_node( - GetterNode(self.gen, op.args[0].concretetype, name)) - elif op.opname == "oosetfield": - receiver = args[0] - name = op.args[1].value - args = args[2:] - if hasattr(self, "self") and op.args[0] == self.self: - # Note that the receiver variable is never used - return "%s := %s." % (name, args[0]) - else: - self.gen.schedule_node( - SetterNode(self.gen, op.args[0].concretetype, name)) - elif op.opname == "direct_call": - # XXX not sure if static methods of a specific class should - # be treated differently. - receiver = "PyFunctions" - name = args[0] - args = args[1:] - self.gen.schedule_node( - FunctionNode(self.gen, op.args[0].value.graph)) + op_method = getattr(self, "op_%s" % op.opname, None) + if op_method is not None: + return op_method(op) else: name = op.opname - receiver = args[0] - args = args[1:] - sel = Selector(name, len(args)) + receiver = self.expr(op.args[0]) + args = [self.expr(arg) for arg in op.args[1:]] + return self.assignment(op, receiver, name, args) + + def assignment(self, op, receiver_name, sel_name, arg_names): + sel = Selector(sel_name, len(arg_names)) if op.opname != "oosend": sel = self.selectormap.get(sel.symbol(), sel) - return "%s := %s %s." \ - % (self.expr(op.result), receiver, sel.signature(args)) + return "%s := %s %s." % (self.expr(op.result), + receiver_name, sel.signature(arg_names)) + + def op_oosend(self, op): + message = op.args[0].value + if hasattr(self, "self") and op.args[1] == self.self: + receiver = "self" + else: + receiver = self.expr(op.args[1]) + args = [self.expr(a) for a in op.args[2:]] + self.gen.schedule_node( + MethodNode(self.gen, op.args[1].concretetype, message)) + return self.assignment(op, receiver, message, args) + + def op_oogetfield(self, op): + receiver = self.expr(op.args[0]) + field_name = op.args[1].value + if hasattr(self, "self") and op.args[0] == self.self: + # Private field access + # Could also directly substitute op.result with name + # everywhere for optimization. + return "%s := %s." % (self.expr(op.result), field_name) + else: + # Public field access + self.gen.schedule_node(GetterNode( + self.gen, op.args[0].concretetype, field_name)) + return self.assignment(op, receiver, field_name, []) + + def op_oosetfield(self, op): + # Note that the result variable is never used + field_name = op.args[1].value + field_value = self.expr(op.args[2]) + if hasattr(self, "self") and op.args[0] == self.self: + # Private field access + return "%s := %s." % (field_name, field_value) + else: + # Public field access + self.gen.schedule_node(SetterNode( + self.gen, op.args[0].concretetype, field_name)) + receiver = self.expr(op.args[0]) + return "%s %s: %s." % (receiver, field_name, field_value) + + def op_direct_call(self, op): + # XXX not sure if static methods of a specific class should + # be treated differently. + receiver = "PyFunctions" + callable_name = self.expr(op.args[0]) + args = [self.expr(a) for a in op.args[1:]] + self.gen.schedule_node( + FunctionNode(self.gen, op.args[0].value.graph)) + return self.assignment(op, receiver, callable_name, args) def render_return(self, args): if len(args) == 2: Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Fri Mar 10 12:01:53 2006 @@ -175,6 +175,21 @@ return i + a.i assert self.run_on_squeak(f, 2) == "6" + def dont_test_classvars(self): + class A: i = 1 + class B(A): i = 2 + def pick(i): + if i == 1: + c = A + else: + c = B + return c + def f(i): + c = pick(i) + return c.i + assert self.run_on_squeak(f, 1) == "1" + assert self.run_on_squeak(f, 2) == "2" + class TestSelector: From auc at codespeak.net Fri Mar 10 12:52:03 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 10 Mar 2006 12:52:03 +0100 (CET) Subject: [pypy-svn] r24212 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060310115203.67509100CD@code0.codespeak.net> Author: auc Date: Fri Mar 10 12:51:56 2006 New Revision: 24212 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/constraint.py pypy/dist/pypy/lib/logic/computation_space/distributor.py pypy/dist/pypy/lib/logic/computation_space/strategies.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: * killed distributor/propagator thread * removed dead code Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Fri Mar 10 12:51:56 2006 @@ -3,34 +3,14 @@ # * [5] add a linear constraint solver (vital for fast # constraint propagation over finite integer domains) # and other kinds of specialized propagators -# * [9] make all propagators live in their own threads and -# be awakened by variable/domains events - - -# Gert Smolka in -# http://www.cetic.be/moz2004/talks/MOZ2004.pdf : -# * Abandon Logic Variables -# * can be bound everywhere -# * malicious consummer can bind tail variable of stream -# * break abstractions -# * unification not needed -# * Have Futures instead -# * Multilisp [Halstead 85] -# * added to Mozart in 1998 -# * refine logic variable into -# * consummer end (future) -# * producer end (promise) -# * dataflow synchronization + by-need synchronization - from threading import Thread, Condition, RLock, local -from state import Succeeded, Distributable, Failed, \ - Unknown, Forsaken +from state import Succeeded, Failed, Unknown from variable import EqSet, CsVar, NoValue, NoDom, \ VariableException, NotAVariable, AlreadyInStore, \ - AlreadyBound, SimpleVar + AlreadyBound from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor @@ -104,9 +84,6 @@ self.bind_lock = RLock() self.var_lock = RLock() self.distributor = DefaultDistributor(self) - # parent/children - self.parent = parent - self.children = set() # mapping from domains to variables self.doms = {} # set of all constraints @@ -122,10 +99,7 @@ self.root = self.var('__root__') # set up the problem self.bind(self.root, problem(self)) - self._init_choose_commit() - self.distributor.start() else: - self.parent.children.add(self) # shared stuff self.vars = parent.vars self.names = parent.names @@ -136,14 +110,6 @@ # ... self.status = Unknown self.distributor = parent.distributor.__class__(self) - self._init_choose_commit() - - def _init_choose_commit(self): - # create a unique choice point - # using two spaceless vars as channels betwen - # space and distributor threads - self.CHOOSE = SimpleVar() - self.STABLE = SimpleVar() #-- utilities & instrumentation ----------------------------- @@ -155,15 +121,6 @@ ret.append(">") return ' '.join(ret) - def __del__(self): - # try to break ref. cycles and help - # threads terminate - self.status = Forsaken - self.parent = None - self.children = None - self.CHOOSE.bind(True) - self.STABLE.bind(True) - def __eq__(self, spc): """space equality defined as : * identity, or @@ -207,12 +164,20 @@ print ' ', str(d.get_values()) print " -- domains --)" + def test_solution(self, sol): + res = True + for _const in self.constraints: + if not _const.test_solution(sol): + print "Solution", sol, "doesn't satisfy", _const + res = False + return res + #-- Computation Space ----------------------------------------- #-- space helpers ----------------------------------------- - def _process(self): + def _propagate(self): """wraps the propagator""" if len(self.event_set): try: @@ -239,33 +204,19 @@ #-- space official API ------------------------------------ def ask(self): - self.STABLE.get() - status = self.status in (Failed, Succeeded) - if status: return self.status + self._propagate() + if self.status in (Failed, Succeeded): + return self.status if self._distributable(): return Alternative(self.distributor.nb_subdomains()) - # should be unreachable - print "DOMS", [(var, self.doms[var]) - for var in self.vars - if self.dom(var) != NoDom] - raise NotImplementedError - def clone(self): - # did you ask before ... ? - assert self.STABLE.is_bound() spc = ComputationSpace(NoProblem, parent=self) print "-- cloning %s to %s --" % (self.id, spc.id) self._notify(event.Clone) - spc._process() - spc.distributor.start() + spc._propagate() return spc - def inject(self, restricting_problem): - """add additional entities into a space""" - restricting_problem(self) - self._process() - def commit(self, choice): """if self is distributable, causes the Choose call in the space to complete and return some_number as a result. This @@ -273,10 +224,7 @@ some_number must satisfy 1= ) record. A commitTo( ) -## % record identifies a Space that is ready to commit to -## % the Ith choice at a choice point. -## % Returns all solutions using either depth-first or -## % breadth-first depending on the value of WhichFirst. -## fun lazy {SolveSpaces Ss} -## case Ss of -## nil then nil -## [] S | SRest then -## % S is either a Space or a commitTo( ) record. -## case S of -## commitTo(S I) then -## Clone = {Space.clone S} -## in -## % Start the Ith branch in the clone of S. -## {Space.commit Clone I} -## {SolveSpaces Clone|SRest} -## else % S is a Space. -## {SolveSpace {Space.ask S} S SRest} -## end -## end -## end - -## % Deal with Space S, which is in state SpaceState -## fun {SolveSpace SpaceState S SRest} -## case SpaceState of -## failed then {SolveSpaces SRest} -## [] succeeded then {Space.merge S}|{SolveSpaces SRest} -## [] alternatives(N) then -## {SolveSpaces {NewSpaceList {Choices S N} SRest}} -## end -## end - -## % The choices are commitTo( ) records. They -## % keep track of the branch to which to commit. -## fun {Choices S N} -## {List.mapInd -## {List.make N} % Generates N elements for Map to use. -## % Keep track of which branch to commit to. -## fun {$ I _} commitTo(S I) end} -## end - -## % Put the Choices at the front or back of the existing list -## % of pending Spaces depending on WhichFirst. For efficiency -## % the lists could be replaced with difference lists. -## fun {NewSpaceList Choices Ss} -## % This is the only place where WhichFirst matters. -## % In depth-first search, the list of pending spaces is a stack. -## if WhichFirst == depth then {Append Choices Ss} -## % In breadth-first search, the list of pending spaces is a queue. -## elseif WhichFirst == breadth then {Append Ss Choices} -## else {Raise traversalSpecificationError(WhichFirst)} nil -## end -## end - -## in -## % The body of Solve -## {SolveSpaces [{Space.new Script}]} -## end - -## % ============================================================== -## % Example to illustrate depth-first vs. breadth-first -## fun {ABC} choice a [] b [] c end end - -## % The "problem" looks at all lists of length =< 3. -## % The "Show" documents the order in which the lists -## % are generated. -## fun {Problem List} -## if {Length List} > 3 then fail end -## {Show List} -## {Problem {Append List [{ABC}]}} -## end +#-- pythonic lazy solve_all + +def lazily_solve_all(space, direction=Depth): + + sp_stack = [] + sp_stack.append(space) + + if direction == Depth: + def collect(space): + sp_stack.append(space) + else: + def collect(space): + sp_stack.insert(0, space) + + while len(sp_stack): + space = sp_stack.pop() + print ' '*len(sp_stack), "ask ..." + status = space.ask() + if status == csp.Succeeded: + print ' '*len(sp_stack), "solution !" + yield space.merge() + elif status == csp.Alternative(2): + print ' '*len(sp_stack), "branches ..." + sp1 = space.clone() + sp1.commit(1) + collect(sp1) + sp2 = space.clone() + sp2.commit(2) + collect(sp2) Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Fri Mar 10 12:51:56 2006 @@ -5,7 +5,11 @@ import computationspace as space import distributor as di import problems -from py.test import raises +try: + from py.test import raises +except ImportError: + def raises(*args): + pass #-- utility --------------------- @@ -341,133 +345,6 @@ assert varset == set([x, y, z, w]) assert constset == set([k1, k2]) - def test_store_satisfiable_success(self): - sp = newspace() - x,y,z = sp.var('x'), sp.var('y'), sp.var('z') - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - k = c.Expression(sp, [x, y, z], 'x == y + z') - sp.add_expression(k) - assert sp.satisfiable(k) == True - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - - def test_store_satisfiable_failure(self): - sp = newspace() - x,y,z = sp.var('x'), sp.var('y'), sp.var('z') - sp.set_dom(x, c.FiniteDomain([1, 2])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - k = c.Expression(sp, [x, y, z], 'x == y + z') - sp.add_expression(k) - assert sp.satisfiable(k) == False - assert sp.dom(x) == c.FiniteDomain([1, 2]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - - def test_satisfiable_many_const_success(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - sp.set_dom(w, c.FiniteDomain([1, 4, 5])) - k1 = c.Expression(sp, [x, y, z], 'x == y + z') - k2 = c.Expression(sp, [z, w], 'z < w') - sp.add_expression(k1) - sp.add_expression(k2) - assert sp.satisfiable(k1) == True - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1, 4, 5]) - assert sp.satisfiable(k2) == True - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1, 4, 5]) - narrowed_doms = sp.get_satisfying_domains(k1) - assert narrowed_doms == {x:c.FiniteDomain([5]), - y:c.FiniteDomain([2]), - z:c.FiniteDomain([3]), - w:c.FiniteDomain([4, 5])} - narrowed_doms = sp.get_satisfying_domains(k2) - assert narrowed_doms == {x:c.FiniteDomain([5]), - y:c.FiniteDomain([2]), - z:c.FiniteDomain([3]), - w:c.FiniteDomain([4, 5])} - - - def test_satisfiable_many_const_failure(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - sp.set_dom(w, c.FiniteDomain([1])) - k1 = c.Expression(sp, [x, y, z], 'x == y + z') - k2 = c.Expression(sp, [z, w], 'z < w') - sp.add_expression(k1) - sp.add_expression(k2) - assert sp.satisfiable(k1) == False - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1]) - assert sp.satisfiable(k2) == False - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1]) - narrowed_doms = sp.get_satisfying_domains(k1) - assert narrowed_doms == {} - narrowed_doms = sp.get_satisfying_domains(k2) - assert narrowed_doms == {} - - def test_satisfy_many_const_failure(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - sp.set_dom(w, c.FiniteDomain([1])) - k1 = c.Expression(sp, [x, y, z], 'x == y + z') - k2 = c.Expression(sp, [z, w], 'z < w') - sp.add_expression(k1) - sp.add_expression(k2) - raises(space.ConsistencyFailure, sp.satisfy, k1) - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1]) - raises(space.ConsistencyFailure, sp.satisfy, k2) - assert sp.dom(x) == c.FiniteDomain([1, 2, 5]) - assert sp.dom(y) == c.FiniteDomain([2, 3]) - assert sp.dom(z) == c.FiniteDomain([3, 4]) - assert sp.dom(w) == c.FiniteDomain([1]) - - def test_satisfy_many_const_success(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - sp.set_dom(w, c.FiniteDomain([1, 4, 5])) - k1 = c.Expression(sp, [x, y, z], 'x == y + z') - k2 = c.Expression(sp, [z, w], 'z < w') - sp.add_expression(k1) - sp.add_expression(k2) - sp.satisfy(k2) - assert sp.dom(x) == c.FiniteDomain([5]) - assert sp.dom(y) == c.FiniteDomain([2]) - assert sp.dom(z) == c.FiniteDomain([3]) - assert sp.dom(w) == c.FiniteDomain([4, 5]) #-- computation spaces ------------------------------- @@ -483,40 +360,11 @@ assert '__root__' in spc.names assert set(['x', 'y', 'z']) == \ set([var.name for var in spc.root.val]) - -# we need to carefully craft some noop problems -# for these tests -# also what is tested below is tested in other places -# so me might want to just forget about it - -## def test_ask_success(self): -## spc = newspace(problems.one_solution_problem) -## assert spc.ask() == space.Succeeded -## assert spc.ask() == space.Succeeded -## def test_ask_failure(self): -## spc = newspace(problems.unsatisfiable_problem) -## assert spc.ask() == space.Failed - def test_ask_alternatives(self): spc = newspace(problems.satisfiable_problem) assert spc.ask() == space.Alternative(2) -## def test_clone_and_process(self): -## spc = newspace(problems.satisfiable_problem) -## assert spc.ask() == space.Alternative(2) -## new_spc = spc.clone() -## #assert spc == new_spc -## assert new_spc.parent == spc -## # following couple of ops superceeded by inject() -## x, y, z = new_spc.find_vars('x', 'y', 'z') -## new_spc.add_constraint([x], 'x == 0') -## new_spc.add_constraint([z, y], 'z == y') -## new_spc.add_constraint([y], 'y < 2') -## new_spc._process() -## assert spc.ask() == space.Alternative(2) -## assert new_spc.ask() == space.Succeeded - def test_clone(self): """checks that a chain of initially s1 = s2 s1 - commit(1) - commit(1) ... @@ -536,8 +384,6 @@ #assert s1 == s2 temp = s2.clone() temp.ask() - assert temp.parent is s2 - assert temp in s2.children s2 = temp s1.commit(1) s2.commit(1) @@ -578,30 +424,37 @@ def test_scheduling_dfs_one_solution(self): sol = strategies.dfs_one(problems.conference_scheduling) - vars = sol.keys() - vars.sort() - sols = [ sol[k] for k in vars ] - result = [('room A', 'day 1 PM'), - ('room A', 'day 2 AM'), - ('room C', 'day 2 PM'), - ('room C', 'day 2 AM'), - ('room C', 'day 1 AM'), - ('room C', 'day 1 PM'), - ('room B', 'day 2 AM'), - ('room B', 'day 1 AM'), - ('room B', 'day 2 PM'), - ('room A', 'day 1 AM'), - ] - - for v, r1, r2 in zip(vars, sols, result): - print v, r1, r2 - assert sols == result - + spc = space.ComputationSpace(problems.conference_scheduling) + assert spc.test_solution( sol ) + - def test_scheduling_all_solutions(self): + def test_scheduling_all_solutions_dfs(self): sols = strategies.solve_all(problems.conference_scheduling) assert len(sols) == 64 - print sols + spc = space.ComputationSpace(problems.conference_scheduling) + for s in sols: + assert spc.test_solution( s ) + + + def test_scheduling_all_solutions_lazily_dfs(self): + sp = space.ComputationSpace(problems.conference_scheduling) + for sol in strategies.lazily_solve_all(sp): + assert sp.test_solution(sol) + + def test_scheduling_all_solutions_bfs(self): + sols = strategies.solve_all(problems.conference_scheduling, + direction=strategies.Breadth) + assert len(sols) == 64 + spc = space.ComputationSpace(problems.conference_scheduling) + for s in sols: + assert spc.test_solution( s ) + + + def test_scheduling_all_solutions_lazily_bfs(self): + sp = space.ComputationSpace(problems.conference_scheduling) + for sol in strategies.lazily_solve_all(sp, direction=strategies.Breadth): + assert sp.test_solution(sol) + def no_test_sudoku(self): #spc = newspace(problems.sudoku) @@ -625,16 +478,3 @@ sol2 = strategies.dfs_one(strategies.sudoku) print "done dfs" #sol2 = [var.val for var in sol] - assert sol2 == [('room A', 'day 1 PM'), - ('room B', 'day 2 PM'), - ('room C', 'day 2 AM'), - ('room C', 'day 2 PM'), - ('room C', 'day 1 AM'), - ('room C', 'day 1 PM'), - ('room A', 'day 2 PM'), - ('room B', 'day 1 AM'), - ('room A', 'day 2 AM'), - ('room A', 'day 1 AM')] - - - Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Fri Mar 10 12:51:56 2006 @@ -73,9 +73,9 @@ self._value_condition.acquire() while not self.is_bound(): t1 = time.time() - self._value_condition.wait(80) + self._value_condition.wait(120) t2 = time.time() - if t2-t1>80: + if t2-t1>120: raise RuntimeError("possible deadlock??") return self.val finally: From cfbolz at codespeak.net Fri Mar 10 13:17:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Mar 2006 13:17:22 +0100 (CET) Subject: [pypy-svn] r24215 - in pypy/dist/pypy/module/stackless: . test Message-ID: <20060310121722.E4141100CF@code0.codespeak.net> Author: cfbolz Date: Fri Mar 10 13:17:21 2006 New Revision: 24215 Modified: pypy/dist/pypy/module/stackless/coroutine.py pypy/dist/pypy/module/stackless/interp_coroutine.py pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Log: (pedronis, cfbolz): add AbstractThunk abstract base class to be used by all places that need to have Thunk objects for coroutines. Modified: pypy/dist/pypy/module/stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/coroutine.py (original) +++ pypy/dist/pypy/module/stackless/coroutine.py Fri Mar 10 13:17:21 2006 @@ -24,9 +24,9 @@ from pypy.interpreter.function import StaticMethod from pypy.module.stackless.stackless_flags import StacklessFlags -from pypy.module.stackless.interp_coroutine import Coroutine, BaseCoState +from pypy.module.stackless.interp_coroutine import Coroutine, BaseCoState, AbstractThunk -class _AppThunk(object): +class _AppThunk(AbstractThunk): def __init__(self, space, costate, w_obj, args): self.space = space Modified: pypy/dist/pypy/module/stackless/interp_coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/interp_coroutine.py (original) +++ pypy/dist/pypy/module/stackless/interp_coroutine.py Fri Mar 10 13:17:21 2006 @@ -92,6 +92,9 @@ def __init__(self): pass +class AbstractThunk(object): + def call(self): + raise NotImplementedError("abstract base class") class Coroutine(Wrappable): @@ -106,6 +109,7 @@ return self.costate.current def bind(self, thunk): + assert isinstance(thunk, AbstractThunk) if self.frame is not None: raise CoroutineDamage if self.parent is None: Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py (original) +++ pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py Fri Mar 10 13:17:21 2006 @@ -3,7 +3,7 @@ """ import os -from pypy.module.stackless.interp_coroutine import costate, Coroutine +from pypy.module.stackless.interp_coroutine import costate, Coroutine, AbstractThunk costate.__init__() @@ -53,7 +53,7 @@ lst.append(7) output('h appended 7') - class T: + class T(AbstractThunk): def __init__(self, func, arg1, arg2): self.func = func self.arg1 = arg1 @@ -93,7 +93,7 @@ def test_coroutine2(): - class TBase: + class TBase(AbstractThunk): def call(self): pass @@ -171,7 +171,7 @@ assert int(data.strip()) == 12345678 def test_kill_raise_del_coro(): - class T: + class T(AbstractThunk): def __init__(self, func, arg): self.func = func self.arg = arg @@ -223,9 +223,7 @@ tree2 = Node(1, Node(3, Node(2))) tree3 = Node(1, Node(2), Node(3)) - class Super: - pass - class Producer(Super): + class Producer(AbstractThunk): def __init__(self, tree, objects, consumer): self.tree = tree self.objects = objects @@ -241,7 +239,7 @@ self.produce(self.tree) while 1: self.consumer.switch() - class Consumer(Super): + class Consumer(AbstractThunk): def __init__(self, tree, objects, producer): self.tree = tree self.objects = objects From cfbolz at codespeak.net Fri Mar 10 13:19:47 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Mar 2006 13:19:47 +0100 (CET) Subject: [pypy-svn] r24216 - pypy/dist/pypy/objspace Message-ID: <20060310121947.C0A1C100CF@code0.codespeak.net> Author: cfbolz Date: Fri Mar 10 13:19:46 2006 New Revision: 24216 Modified: pypy/dist/pypy/objspace/logic.py Log: (cfbolz, pedronis): added an implementation of uthreads that use stackless and interpreter-level coroutines. seems to be translatable and it is possible to run the examples. Sidenode: it seems to be possible to use greenlets to implement interpreter-level coroutines at least to some extend. Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Fri Mar 10 13:19:46 2006 @@ -1,31 +1,130 @@ from pypy.objspace.proxy import patch_space_in_place from pypy.interpreter import gateway, baseobjspace, argument from pypy.interpreter.error import OperationError +from pypy.rpython.objectmodel import we_are_translated -USE_GREENLETS = False +USE_COROUTINES = True +HAVE_GREENLETS = True try: from py.magic import greenlet except ImportError: - USE_GREENLETS = False + HAVE_GREENLETS = False -if USE_GREENLETS: - runnable_uthreads = {} - uthreads_blocked_on = {} - main_greenlet = greenlet.getcurrent() +def have_uthreads(): + if USE_COROUTINES: + if we_are_translated(): + return True + else: + return HAVE_GREENLETS + return False + +if USE_COROUTINES: + from pypy.module.stackless.interp_coroutine import Coroutine, AbstractThunk + + class ScheduleState(object): + def __init__(self): + self.runnable_uthreads = {} + self.uthreads_blocked_on = {} + + def pop_runnable_thread(self): + # umpf, no popitem in RPython + key = None + for key, item in self.runnable_uthreads.iteritems(): + break + del self.runnable_uthreads[key] + return key + + def add_to_runnable(self, uthread): + self.runnable_uthreads[uthread] = True + + def remove_from_runnable(self, uthread): + del self.runnable_uthreads[uthread] + + def have_runnable_threads(self): + return bool(self.runnable_uthreads) + + def have_blocked_threads(self): + return bool(self.uthreads_blocked_on) + + def add_to_blocked(self, w_var, uthread): + if w_var in self.uthreads_blocked_on: + blocked = self.uthreads_blocked_on[w_var] + else: + blocked = [] + self.uthreads_blocked_on[w_var] = blocked + blocked.append(uthread) + + def pop_blocked_on(self, w_var): + if w_var not in self.uthreads_blocked_on: + return [] + blocked = self.uthreads_blocked_on[w_var] + del self.uthreads_blocked_on[w_var] + return blocked + + schedule_state = ScheduleState() + + class Thunk(AbstractThunk): + def __init__(self, space, w_callable, args, w_Result): + self.space = space + self.w_callable = w_callable + self.args = args + self.w_Result = w_Result # the upper-case R is because it is a logic variable + + def call(self): + bind(self.space, self.w_Result, + self.space.call_args(self.w_callable, self.args)) + + class GreenletCoroutine(object): + def bind(self, thunk): + self.greenlet = greenlet(thunk.call) + + def switch(self): + self.greenlet.switch() + + def is_alive(self): + return bool(self.greenlet) + + def getcurrent(): + result = GreenletCoroutine() + result.greenlet = greenlet.getcurrent() + return result + getcurrent = staticmethod(getcurrent) + + def __hash__(self): + return hash(self.greenlet) + + def __eq__(self, other): + return self.greenlet == other.greenlet + + def __ne__(self, other): + return not (self == other) + + def construct_coroutine(): + if we_are_translated(): + return Coroutine() + else: + return GreenletCoroutine() + + def get_current_coroutine(): + if we_are_translated(): + return Coroutine.getcurrent() + else: + return GreenletCoroutine.getcurrent() def uthread(space, w_callable, __args__): + args = __args__.normalize() w_Result = W_Var() - def run(): - space.eq(w_Result, space.call_args(w_callable, __args__)) - gr = greenlet(run) - current = greenlet.getcurrent() - runnable_uthreads[current] = True - gr.switch() - while runnable_uthreads: - next_greenlet, _ = runnable_uthreads.popitem() - if next_greenlet and next_greenlet is not current: - runnable_uthreads[current] = True - next_greenlet.switch() + thunk = Thunk(space, w_callable, args, w_Result) + coro = construct_coroutine() + coro.bind(thunk) + current = get_current_coroutine() + schedule_state.add_to_runnable(current) + coro.switch() + while schedule_state.have_runnable_threads(): + next_coro = schedule_state.pop_runnable_thread() + if next_coro.is_alive() and next_coro != current: + schedule_state.add_to_runnable(current) + next_coro.switch() return w_Result app_uthread = gateway.interp2app(uthread, unwrap_spec=[baseobjspace.ObjSpace, baseobjspace.W_Root, @@ -54,16 +153,16 @@ w_obj = w_last.w_bound_to if w_obj is None: # XXX here we would have to suspend the current thread - if not USE_GREENLETS: + if not have_uthreads(): raise OperationError(space.w_RuntimeError, space.wrap("trying to perform an operation on an unbound variable")) else: - current = greenlet.getcurrent() - uthreads_blocked_on.setdefault(w_last, []).append(current) - while runnable_uthreads: - next_greenlet, _ = runnable_uthreads.popitem() - if next_greenlet: - next_greenlet.switch() + current = get_current_coroutine() + schedule_state.add_to_blocked(w_last, current) + while schedule_state.have_runnable_threads(): + next_coro = schedule_state.pop_runnable_thread() + if next_coro.is_alive(): + next_coro.switch() # there is a value here now break else: @@ -117,10 +216,10 @@ w_next = w_curr.w_bound_to w_curr.w_bound_to = w_obj w_curr = w_next - if USE_GREENLETS: - now_unblocked_uthreads = uthreads_blocked_on.pop(w_last, []) + if have_uthreads(): + now_unblocked_uthreads = schedule_state.pop_blocked_on(w_last) for uthread in now_unblocked_uthreads: - runnable_uthreads[uthread] = True + schedule_state.add_to_runnable(uthread) return space.w_None app_bind = gateway.interp2app(bind) @@ -250,20 +349,18 @@ space.wrap(app_is_unbound)) space.setitem(space.builtin.w_dict, space.wrap('bind'), space.wrap(app_bind)) - if USE_GREENLETS: + if USE_COROUTINES: + import os def exitfunc(): - current = greenlet.getcurrent() - while runnable_uthreads: - next_greenlet, _ = runnable_uthreads.popitem() - if next_greenlet and next_greenlet is not current: - runnable_uthreads[current] = True - next_greenlet.switch() - del runnable_uthreads[current] - if uthreads_blocked_on: - print "there are still blocked uthreads!" - for var, blocked in uthreads_blocked_on.iteritems(): - print var, blocked - assert 0 + current = get_current_coroutine() + while schedule_state.have_runnable_threads(): + next_coro = schedule_state.pop_runnable_thread() + if next_coro.is_alive and next_coro != current: + schedule_state.add_to_runnable(current) + next_coro.switch() + schedule_state.remove_from_runnable(current) + if schedule_state.have_blocked_threads(): + os.write(2, "there are still blocked uthreads!") app_exitfunc = gateway.interp2app(exitfunc, unwrap_spec=[]) space.setitem(space.sys.w_dict, space.wrap("exitfunc"), space.wrap(app_exitfunc)) space.setitem(space.builtin.w_dict, space.wrap('uthread'), From mwh at codespeak.net Fri Mar 10 13:27:27 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 10 Mar 2006 13:27:27 +0100 (CET) Subject: [pypy-svn] r24217 - in pypy/dist/pypy: rpython/memory translator/c/test Message-ID: <20060310122727.BEB47100CF@code0.codespeak.net> Author: mwh Date: Fri Mar 10 13:27:26 2006 New Revision: 24217 Modified: pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: raise MemoryError if the length * item_size calculation overflows. this doesn't tackle the issue of raw_malloc actually returning NULL, but I'm running on a linux box with lots of swap, that's not actually going to happen, right? (quiet there at the back!) Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Fri Mar 10 13:27:26 2006 @@ -4,6 +4,7 @@ from pypy.rpython.memory import lltypesimulation from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rpython import rarithmetic import sys @@ -123,7 +124,11 @@ self.collect() size = self.fixed_size(typeid) if self.is_varsize(typeid): - size += length * self.varsize_item_sizes(typeid) + try: + varsize = rarithmetic.ovfcheck(length * self.varsize_item_sizes(typeid)) + except OverflowError: + raise MemoryError + size += varsize size_gc_header = self.size_gc_header() result = raw_malloc(size + size_gc_header) ## print "mallocing %s, size %s at %s" % (typeid, size, result) Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Fri Mar 10 13:27:26 2006 @@ -295,3 +295,9 @@ assert res == 44 + def test_framework_malloc_failure(self): + def f(): + a = [1] * (sys.maxint//2) + return len(a) + a[0] + fn = self.getcompiled(f) + py.test.raises(MemoryError, fn) From nik at codespeak.net Fri Mar 10 13:41:32 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 10 Mar 2006 13:41:32 +0100 (CET) Subject: [pypy-svn] r24220 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060310124132.39DBC100D3@code0.codespeak.net> Author: nik Date: Fri Mar 10 13:41:30 2006 New Revision: 24220 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: slightly adapt a test to use instance variables with underscores. fix stuff to make underscores go away in squeak code. a problem remains with possible nameclashes. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Fri Mar 10 13:41:30 2006 @@ -174,6 +174,12 @@ class_name, category, datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) + def unique_field(self, INSTANCE, field_name): + # XXX for now we ignore the issue of nameclashes between + # field names. It's not so simple because superclasses must + # be considered, too. + return camel_case(field_name) + class ClassNode(CodeNode): def __init__(self, gen, INSTANCE): @@ -191,8 +197,9 @@ yield "%s subclass: #%s" % ( self.gen.nameof_Instance(self.INSTANCE._superclass), self.gen.nameof_Instance(self.INSTANCE)) - yield " instanceVariableNames: '%s'" % \ - ' '.join(self.INSTANCE._fields.iterkeys()) + fields = [self.unique_field(self.INSTANCE, f) for f in + self.INSTANCE._fields.iterkeys()] + yield " instanceVariableNames: '%s'" % ' '.join(fields) yield " classVariableNames: ''" yield " poolDictionaries: ''" yield " category: 'PyPy-Test'!" @@ -283,30 +290,30 @@ return self.assignment(op, receiver, message, args) def op_oogetfield(self, op): + INST = op.args[0].concretetype receiver = self.expr(op.args[0]) - field_name = op.args[1].value + field_name = self.unique_field(INST, op.args[1].value) if hasattr(self, "self") and op.args[0] == self.self: # Private field access # Could also directly substitute op.result with name # everywhere for optimization. - return "%s := %s." % (self.expr(op.result), field_name) + return "%s := %s." % (self.expr(op.result), camel_case(field_name)) else: # Public field access - self.gen.schedule_node(GetterNode( - self.gen, op.args[0].concretetype, field_name)) + self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) return self.assignment(op, receiver, field_name, []) def op_oosetfield(self, op): # Note that the result variable is never used - field_name = op.args[1].value + INST = op.args[0].concretetype + field_name = self.unique_field(INST, op.args[1].value) field_value = self.expr(op.args[2]) if hasattr(self, "self") and op.args[0] == self.self: # Private field access return "%s := %s." % (field_name, field_value) else: # Public field access - self.gen.schedule_node(SetterNode( - self.gen, op.args[0].concretetype, field_name)) + self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) receiver = self.expr(op.args[0]) return "%s %s: %s." % (receiver, field_name, field_value) Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Fri Mar 10 13:41:30 2006 @@ -163,16 +163,16 @@ def test_getfield_setfield(self): class A: def set(self, i): - self.i = i + self.i_var = i def inc(self): - self.i = self.i + 1 + self.i_var = self.i_var + 1 def f(i): a = A() a.set(i) - i = a.i - a.i = 3 + i = a.i_var + a.i_var = 3 a.inc() - return i + a.i + return i + a.i_var assert self.run_on_squeak(f, 2) == "6" def dont_test_classvars(self): From ludal at codespeak.net Fri Mar 10 13:44:19 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Fri, 10 Mar 2006 13:44:19 +0100 (CET) Subject: [pypy-svn] r24221 - pypy/dist/pypy/lib/logic/gecode_wrapper Message-ID: <20060310124419.65029100D4@code0.codespeak.net> Author: ludal Date: Fri Mar 10 13:44:16 2006 New Revision: 24221 Added: pypy/dist/pypy/lib/logic/gecode_wrapper/README Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h pypy/dist/pypy/lib/logic/gecode_wrapper/main.c pypy/dist/pypy/lib/logic/gecode_wrapper/reine.py pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.cc pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh Log: (ludal, ale, Gregoire Dooms) first draft implementation of a Python propagator called back from gecode engine Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/Makefile Fri Mar 10 13:44:16 2006 @@ -1,6 +1,7 @@ -CXXFLAGS=$(shell pkg-config --cflags gecode gecode-minimodel gecode-search) +CXXFLAGS=$(shell pkg-config --cflags gecode gecode-minimodel gecode-search) -g +CFLAGS=-g LDFLAGS=$(shell pkg-config --libs gecode gecode-minimodel gecode-search) @@ -9,6 +10,6 @@ libgecode_wrap.so: gecode_wrap.o space_wrap.o gecode_wrap.h space_wrap.hh - g++ -o $@ $(LDFLAGS) -shared $< + g++ -o $@ $(LDFLAGS) -shared gecode_wrap.o space_wrap.o Added: pypy/dist/pypy/lib/logic/gecode_wrapper/README ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/README Fri Mar 10 13:44:16 2006 @@ -0,0 +1,8 @@ +make +python reine.py 8 + +or +LD_LIBRARY_PATH=. ./reine 10 + +(need to get ctypes, and gecode library) +apt-get install libgecode0-dev Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.cc Fri Mar 10 13:44:16 2006 @@ -45,6 +45,7 @@ return _eng->next(); } + void space_values( void* spc, int n, int* vars, int* values ) { MySpace* _spc = static_cast(spc); @@ -56,3 +57,60 @@ MySpace* _spc = static_cast(spc); delete _spc; } + + + +void* new_propagator( void* spc, PropagatorCallback cb ) +{ + MySpace* _spc = static_cast(spc); + return (void*)new (_spc) MyPropagator(_spc, cb); +} + +int propagator_create_int_view( void* prp, int var ) +{ + MyPropagator* _prp = static_cast(prp); + return _prp->add_int_view( var ); +} + +int int_view_lq( void* prp, int view, int value ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.lq( _prp->home, value ); +} + +int int_view_gq( void* prp, int view, int value ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.gq( _prp->home, value ); +} + +int int_view_min( void* prp, int view ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.min(); +} + +int int_view_max( void* prp, int view ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.max( ); +} + +int int_view_val( void* prp, int view ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.val( ); +} + +int int_view_assigned( void* prp, int view ) +{ + MyPropagator* _prp = static_cast(prp); + IntView& _view = _prp->get_int_view( view ); + return _view.assigned( ); +} + Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap.h Fri Mar 10 13:44:16 2006 @@ -25,6 +25,20 @@ void space_release( void* spc ); + /* propagators */ + + typedef int (*PropagatorCallback)(void*); + void* new_propagator( void* spc, PropagatorCallback cb ); + + int propagator_create_int_view( void* prp, int var ); + + int int_view_lq( void* prp, int view, int value ); + int int_view_gq( void* prp, int view, int value ); + int int_view_min( void* prp, int view ); + int int_view_max( void* prp, int view ); + int int_view_val( void* prp, int view ); + int int_view_assigned( void* prp, int view ); + #ifdef __cplusplus }; #endif Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/main.c ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/main.c (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/main.c Fri Mar 10 13:44:16 2006 @@ -15,6 +15,9 @@ }; + + + int main( int argc, char** argv ) { int coefs[2] = { 1, -1}; Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/reine.py ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/reine.py (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/reine.py Fri Mar 10 13:44:16 2006 @@ -5,9 +5,27 @@ gecode = cdll.LoadLibrary("./libgecode_wrap.so") IRT_NQ = 1 +ES_FAILED = -1 # < Execution has resulted in failure +ES_NOFIX = 0 # < Propagation has not computed fixpoint +ES_OK = 0 # < Execution is okay +ES_FIX = 1 # < Propagation has computed fixpoint +ES_SUBSUMED = 2 # < %Propagator is subsumed (entailed) + import sys +PROPCB = CFUNCTYPE(c_int, c_void_p) + +def null_propagator( prop ): + x = gecode.int_view_assigned( prop, 0 ) + y = gecode.int_view_assigned( prop, 1 ) + print "Assigned", x, y + return ES_OK + + +nullpropcb = PROPCB(null_propagator) + + N = int(sys.argv[1]) spc = gecode.new_space() @@ -29,6 +47,13 @@ gecode.space_linear( spc, 2, coefs, qpair, IRT_NQ, i-j ) gecode.space_linear( spc, 2, coefs, qpair, IRT_NQ, j-i ) + +myprop = gecode.new_propagator( spc, nullpropcb ) + +gecode.propagator_create_int_view( myprop, 0 ) +gecode.propagator_create_int_view( myprop, N-1 ) + + gecode.space_branch( spc ) engine = gecode.new_dfs( spc, 5, 2 ) @@ -40,7 +65,7 @@ sol = gecode.search_next( engine ) if not sol: break - if nsol%10 == 0: + if nsol%1 == 0: print "Sol", nsol gecode.space_values( sol, N, qvars, result ) for i in result: Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.cc ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.cc (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.cc Fri Mar 10 13:44:16 2006 @@ -39,10 +39,54 @@ return new MyDFSEngine( spc, c_d, c_a ); } -MySpace* search_next( void* _search ) + + +MyPropagator::MyPropagator(MySpace* _home, PropagatorCallback cb ) + : Propagator(_home), _cb(cb), home(_home) { - MySearchEngine* search = static_cast(_search); - return search->next(); } +ExecStatus +MyPropagator::post(Space* home) { + /* post domain reduction done from python */ + return ES_OK; +} + + +MyPropagator::MyPropagator(Space* _home, bool share, MyPropagator& p) + : Propagator(_home,share,p), home(static_cast(_home)), _cb(p._cb) +{ + IntViewVectIterator it; + for(it=p._int_views.begin();it!=p._int_views.end();++it) { + _int_views.push_back( IntView() ); + _int_views.back().update(_home, share, *it ); + } +} + +Actor* +MyPropagator::copy(Space* home, bool share) { + return new (home) MyPropagator(home,share,*this); +} + +ExecStatus +MyPropagator::propagate(Space* home) { + ExecStatus status; + status = (ExecStatus)_cb( this ); + return status; +} + +int +MyPropagator::add_int_view( int var ) +{ + IntVar& intvar = home->get_int_var( var ); + _int_views.push_back( IntView( intvar ) ); + _int_views.back().subscribe( home, this, PC_INT_BND ); + return _int_views.size()-1; +} + +PropCost +MyPropagator::cost(void) const +{ + return PC_MAX; +} Modified: pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh ============================================================================== --- pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh (original) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/space_wrap.hh Fri Mar 10 13:44:16 2006 @@ -11,10 +11,12 @@ #include "kernel.hh" #include "int.hh" #include "search.hh" +#include "gecode_wrap.h" /* */ using namespace Gecode; +using namespace Gecode::Int; using namespace std; class Unimplemented : public exception {}; @@ -96,6 +98,8 @@ cout << endl; } + IntVar& get_int_var( int n ) { return _int_vars[n]; } + protected: vector< IntVar > _int_vars; @@ -115,4 +119,29 @@ DFS dfs; }; + +typedef vector IntViewVect; +typedef IntViewVect::const_iterator IntViewVectConstIterator; +typedef IntViewVect::iterator IntViewVectIterator; + +class MyPropagator : public Propagator { +public: + MyPropagator(MySpace* home, PropagatorCallback cb ); + MyPropagator(Space* home, bool share, MyPropagator& p); + virtual ExecStatus propagate (Space *); + virtual PropCost cost (void) const; + Actor* copy(Space* home, bool share); + ExecStatus post(Space* home); + + int add_int_view( int var ); + IntView& get_int_view( int view ) { return _int_views[view]; } + + MySpace* home; +protected: + IntViewVect _int_views; + PropagatorCallback _cb; +}; + + + #endif From nik at codespeak.net Fri Mar 10 18:26:11 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 10 Mar 2006 18:26:11 +0100 (CET) Subject: [pypy-svn] r24234 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060310172611.9090D100DD@code0.codespeak.net> Author: nik Date: Fri Mar 10 18:26:05 2006 New Revision: 24234 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: some quick hacking to make constant instances work for the simple test cases so far. this is maybe too brittle for the general case. need to think about a more permanent solution now. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Fri Mar 10 18:26:05 2006 @@ -32,6 +32,7 @@ self.unique_name_mapping = {} self.pending_nodes = [] self.generated_nodes = set() + self.constant_insts = {} if conftest.option.view: self.translator.view() @@ -41,6 +42,8 @@ self.filename = '%s.st' % graph.name file = self.sqdir.join(self.filename).open('w') self.gen_source(file) + self.pending_nodes.append(SetupNode(self, self.constant_insts)) + self.gen_source(file) file.close() def gen_source(self, file): @@ -99,8 +102,8 @@ squeak_class_name = self.unique_name(INSTANCE, class_name) return "Py%s" % squeak_class_name - def nameof__instance(self, inst): - return self.nameof_Instance(inst._TYPE) + def nameof__class(self, class_): + return self.nameof_Instance(class_._INSTANCE) def nameof__callable(self, callable): return self.nameof_function(callable.graph.func) @@ -182,9 +185,12 @@ class ClassNode(CodeNode): - def __init__(self, gen, INSTANCE): + def __init__(self, gen, INSTANCE, class_vars=None): self.gen = gen self.INSTANCE = INSTANCE + self.class_vars = [] # XXX should probably go away + if class_vars is not None: + self.class_vars = class_vars self.hash_key = INSTANCE def dependencies(self): @@ -200,7 +206,7 @@ fields = [self.unique_field(self.INSTANCE, f) for f in self.INSTANCE._fields.iterkeys()] yield " instanceVariableNames: '%s'" % ' '.join(fields) - yield " classVariableNames: ''" + yield " classVariableNames: '%s'" % ' '.join(self.class_vars) yield " poolDictionaries: ''" yield " category: 'PyPy-Test'!" @@ -257,6 +263,11 @@ if isinstance(v, Variable): return camel_case(v.name) elif isinstance(v, Constant): + if isinstance(v.concretetype, Instance): + const_id = self.gen.unique_name( + v, "const_%s" % self.gen.nameof(v.value._TYPE)) + self.gen.constant_insts[v] = const_id + return "(PyConstants getConstant: '%s')" % const_id return self.gen.nameof(v.value) else: raise TypeError, "expr(%r)" % (v,) @@ -317,6 +328,9 @@ receiver = self.expr(op.args[0]) return "%s %s: %s." % (receiver, field_name, field_value) + def op_oodowncast(self, op): + return "%s := %s." % (self.expr(op.result), self.expr(op.args[0])) + def op_direct_call(self, op): # XXX not sure if static methods of a specific class should # be treated differently. @@ -457,3 +471,65 @@ yield " ^%s" % self.field_name yield "! !" +class FieldInitializerNode(CodeNode): + + def __init__(self, gen, INSTANCE): + self.gen = gen + self.INSTANCE = INSTANCE + self.hash_key = ("fieldinit", INSTANCE) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "initializers") + fields = self.INSTANCE._allfields() + sel = Selector("field_init", len(fields)) + arg_names = ["a%s" % i for i in range(len(fields))] + yield sel.signature(arg_names) + for field_name, arg_name in zip(fields.keys(), arg_names): + yield " %s := %s." % ( + self.unique_field(self.INSTANCE, field_name), + arg_name) + yield "! !" + +class SetupNode(CodeNode): + + CONSTANTS = Instance("Constants", ROOT) + + def __init__(self, gen, constants): + self.gen = gen + self.constants = constants + self.hash_key = "setup" + + def dependencies(self): + # Important: Field initializers for the *runtime* type + return [FieldInitializerNode(self.gen, c.value._TYPE) + for c in self.constants.iterkeys()] + \ + [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] + + def render(self): + yield self.render_fileout_header("PyConstants class", "internals") + sel = Selector("setupConstants", 0) + yield sel.signature([]) + yield " Constants := Dictionary new." + for const, const_id in self.constants.iteritems(): + INST = const.value._TYPE + class_name = self.gen.nameof(INST) + field_names = INST._allfields().keys() + field_values = [self.gen.nameof(getattr(const.value, f)) + for f in field_names] + init_sel = Selector("field_init", len(field_values)) + yield " Constants at: '%s' put: (%s new %s)." \ + % (const_id, class_name, + init_sel.signature(field_values)) + yield "! !" + yield "" + + yield self.render_fileout_header("PyConstants class", "internals") + sel = Selector("getConstant", 1) + yield sel.signature(["constId"]) + yield " ^ Constants at: constId" + yield "! !" + Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Fri Mar 10 18:26:05 2006 @@ -18,6 +18,8 @@ except AttributeError: pass t = TranslationContext() t.buildannotator().build_types(func, args) + if conftest.option.view: + t.viewcg() t.buildrtyper(type_system="ootype").specialize() if conftest.option.view: t.viewcg() @@ -51,6 +53,7 @@ [(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil] whileTrue: [arguments add: arg asInteger]. +PyConstants setupConstants. result := (PyFunctions perform: selector withArguments: arguments asArray). stdout := StandardFileStream fileNamed: '/dev/stdout'. stdout nextPutAll: result asString. @@ -175,7 +178,7 @@ return i + a.i_var assert self.run_on_squeak(f, 2) == "6" - def dont_test_classvars(self): + def test_classvars(self): class A: i = 1 class B(A): i = 2 def pick(i): From tismer at codespeak.net Sat Mar 11 07:36:00 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 11 Mar 2006 07:36:00 +0100 (CET) Subject: [pypy-svn] r24241 - pypy/dist/pypy/interpreter Message-ID: <20060311063600.B92A8100D7@code0.codespeak.net> Author: tismer Date: Sat Mar 11 07:35:43 2006 New Revision: 24241 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: please comment about the frame stack consideration. starting coroutine support. Some kind of subcontexts is needed, but it is not clear what fits us best. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sat Mar 11 07:35:43 2006 @@ -15,6 +15,13 @@ self.ticker = 0 self.compiler = space.createcompiler() + # XXX + # I think that it is wrong to hide frames here. The stack should + # contain all the frames, because we need them for pickling. + # better to do the hiding when the stack is accessed. This implies that + # we have an explicit frame depth counter. + # please comment/correct me! (chris) + def enter(self, frame): if self.framestack.depth() > self.space.sys.recursionlimit: raise OperationError(self.space.w_RuntimeError, @@ -34,6 +41,9 @@ if not frame.hide(): self.framestack.pop() + # coroutine support + # XXX still trying and thinking hard + def get_builtin(self): try: return self.framestack.top().builtin From pedronis at codespeak.net Sun Mar 12 15:02:54 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 12 Mar 2006 15:02:54 +0100 (CET) Subject: [pypy-svn] r24263 - in pypy/dist/pypy/translator: c c/src tool Message-ID: <20060312140254.73BBD100A8@code0.codespeak.net> Author: pedronis Date: Sun Mar 12 15:02:51 2006 New Revision: 24263 Added: pypy/dist/pypy/translator/tool/__thread_test.c (contents, props changed) Modified: pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/src/stack.h pypy/dist/pypy/translator/c/src/thread.h pypy/dist/pypy/translator/tool/cbuild.py Log: use __thread with gcc when possible. At the moment doesn't seem to make any significant difference for our speed. Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Sun Mar 12 15:02:51 2006 @@ -7,6 +7,7 @@ from pypy.translator.tool.cbuild import compile_c_module from pypy.translator.tool.cbuild import build_executable, CCompiler from pypy.translator.tool.cbuild import import_module_from_directory +from pypy.translator.tool.cbuild import check_under_under_thread from pypy.rpython.lltypesystem import lltype from pypy.tool.udir import udir from pypy.tool import isolate @@ -56,6 +57,8 @@ db.complete() return db + have___thread = None + def generate_source(self, db=None): assert self.c_source_filename is None translator = self.translator @@ -70,6 +73,10 @@ self.targetdir = targetdir defines = {} # defines={'COUNT_OP_MALLOCS': 1} + if CBuilder.have___thread is None: + CBuilder.have___thread = check_under_under_thread() + if CBuilder.have___thread: + defines['HAVE___THREAD'] = 1 if not self.standalone: from pypy.translator.c.symboltable import SymbolTable self.symboltable = SymbolTable() Modified: pypy/dist/pypy/translator/c/src/stack.h ============================================================================== --- pypy/dist/pypy/translator/c/src/stack.h (original) +++ pypy/dist/pypy/translator/c/src/stack.h Sun Mar 12 15:02:51 2006 @@ -37,7 +37,7 @@ static volatile char *stack_base_pointer = NULL; static long stack_min = 0; static long stack_max = 0; - static RPyThreadTLS stack_base_pointer_key; + static RPyThreadStaticTLS stack_base_pointer_key; /* Check that the stack is less than MAX_STACK_SIZE bytes bigger than the value recorded in stack_base_pointer. The base pointer is updated to the current value if it is still NULL @@ -58,7 +58,7 @@ /* XXX We assume that initialization is performed early, when there is still only one thread running. This allows us to ignore race conditions here */ - char *errmsg = RPyThreadTLS_Create(&stack_base_pointer_key); + char *errmsg = RPyThreadStaticTLS_Create(&stack_base_pointer_key); if (errmsg) { /* XXX should we exit the process? */ fprintf(stderr, "Internal PyPy error: %s\n", errmsg); @@ -70,7 +70,7 @@ stack_min = -MAX_STACK_SIZE; } - baseptr = (char *) RPyThreadTLS_Get(stack_base_pointer_key); + baseptr = (char *) RPyThreadStaticTLS_Get(stack_base_pointer_key); if (baseptr != NULL) { diff = &local - baseptr; if (stack_min <= diff && diff <= stack_max) { @@ -92,7 +92,7 @@ /* update the stack base pointer to the current value */ baseptr = &local; - RPyThreadTLS_Set(stack_base_pointer_key, baseptr); + RPyThreadStaticTLS_Set(stack_base_pointer_key, baseptr); stack_base_pointer = baseptr; return 0; } Modified: pypy/dist/pypy/translator/c/src/thread.h ============================================================================== --- pypy/dist/pypy/translator/c/src/thread.h (original) +++ pypy/dist/pypy/translator/c/src/thread.h Sun Mar 12 15:02:51 2006 @@ -17,3 +17,21 @@ #ifdef NT_THREADS #include "thread_nt.h" #endif + +#ifdef HAVE___THREAD + +#define RPyThreadStaticTLS __thread void * +#define RPyThreadStaticTLS_Create(tls) NULL +#define RPyThreadStaticTLS_Get(tls) tls +#define RPyThreadStaticTLS_Set(tls, value) tls = value + +#endif + +#ifndef RPyThreadStaticTLS + +#define RPyThreadStaticTLS RPyThreadTLS +#define RPyThreadStaticTLS_Create(key) RPyThreadTLS_Create(key) +#define RPyThreadStaticTLS_Get(key) RPyThreadTLS_Get(key) +#define RPyThreadStaticTLS_Set(key, value) RPyThreadTLS_Set(key, value) + +#endif Added: pypy/dist/pypy/translator/tool/__thread_test.c ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/tool/__thread_test.c Sun Mar 12 15:02:51 2006 @@ -0,0 +1,35 @@ +#include +#include + +#define N 100000000 + +#if defined(__GNUC__) && defined(_POSIX_THREADS) +#include + +void * th_f(void *x) { + volatile int * n = (volatile int *)x; + static __thread int i = 0; + int delta; + delta = *n; + for (; i < N; i++) { + *n += delta; + } + return NULL; +} + +int nbs[] = {2, 3}; + +int main() { + pthread_t t0, t1; + pthread_create(&t0, NULL, th_f, &nbs[0]); + pthread_create(&t1, NULL, th_f, &nbs[1]); + pthread_join(t0, NULL); + pthread_join(t1, NULL); + printf("1= %d\n", nbs[0]); + printf("2= %d\n", nbs[1]); + return !(nbs[0] == (N+1)*2 && nbs[1] == (N+1)*3); +} + +#else +#error "Meaningful only with GCC (+ POSIX Threads)" +#endif Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Sun Mar 12 15:02:51 2006 @@ -354,3 +354,24 @@ return False else: return True + +def check_under_under_thread(): + from pypy.tool.udir import udir + cfile = py.path.local(autopath.this_dir).join('__thread_test.c') + fsource = cfile.open('r') + source = fsource.read() + fsource.close() + cfile = udir.join('__thread_test.c') + fsource = cfile.open('w') + fsource.write(source) + fsource.close() + try: + exe = build_executable([str(cfile)], + noerr=True) + py.process.cmdexec(exe) + except (KeyboardInterrupt, SystemExit): + raise + except: + return False + else: + return True From mwh at codespeak.net Mon Mar 13 00:02:00 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 13 Mar 2006 00:02:00 +0100 (CET) Subject: [pypy-svn] r24272 - pypy/dist/pypy/rpython/memory Message-ID: <20060312230200.0170D100A8@code0.codespeak.net> Author: mwh Date: Mon Mar 13 00:02:00 2006 New Revision: 24272 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: reimplement for the framwork gcs a hack to add an extra byte to all strings. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Mon Mar 13 00:02:00 2006 @@ -9,6 +9,7 @@ from pypy.rpython import rmodel, rptr, annlowlevel from pypy.rpython.memory import gc, lladdress from pypy.rpython.annlowlevel import MixLevelHelperAnnotator +from pypy.rpython.rstr import STR import sets, os EXCEPTION_RAISING_OPS = ['direct_call', 'indirect_call'] @@ -827,6 +828,8 @@ info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) else: info["fixedsize"] = ofs1 + llmemory.sizeof(lltype.Signed) + if TYPE is STR: + info["fixedsize"] = llmemory.sizeof(TYPE, 1) else: ARRAY = TYPE info["ofstolength"] = llmemory.ArrayLengthOffset(ARRAY) From tismer at codespeak.net Mon Mar 13 04:06:00 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 13 Mar 2006 04:06:00 +0100 (CET) Subject: [pypy-svn] r24279 - pypy/dist/pypy/translator/c Message-ID: <20060313030600.BE588100BC@code0.codespeak.net> Author: tismer Date: Mon Mar 13 04:05:49 2006 New Revision: 24279 Modified: pypy/dist/pypy/translator/c/pyobj.py Log: hoppla! I forgot to remove old code Modified: pypy/dist/pypy/translator/c/pyobj.py ============================================================================== --- pypy/dist/pypy/translator/c/pyobj.py (original) +++ pypy/dist/pypy/translator/c/pyobj.py Mon Mar 13 04:05:49 2006 @@ -99,17 +99,6 @@ return name def nameof_module(self, value): - assert value is os or not hasattr(value, "__file__") or \ - not (value.__file__.endswith('.pyc') or - value.__file__.endswith('.py') or - value.__file__.endswith('.pyo')), \ - "%r is not a builtin module (probably :)"%value - name = self.uniquename('mod%s'%value.__name__) - self.initcode_python(name, "__import__(%r)" % (value.__name__,)) - return name - - # try to build valid imports for external stuff - def nameof_module(self, value): easy = value is os or not hasattr(value, "__file__") or \ not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py') or From tismer at codespeak.net Mon Mar 13 04:59:51 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 13 Mar 2006 04:59:51 +0100 (CET) Subject: [pypy-svn] r24280 - pypy/dist/pypy/translator/test Message-ID: <20060313035951.45BE5100BC@code0.codespeak.net> Author: tismer Date: Mon Mar 13 04:59:40 2006 New Revision: 24280 Modified: pypy/dist/pypy/translator/test/test_extension.py Log: more tests, checking different types Modified: pypy/dist/pypy/translator/test/test_extension.py ============================================================================== --- pypy/dist/pypy/translator/test/test_extension.py (original) +++ pypy/dist/pypy/translator/test/test_extension.py Mon Mar 13 04:59:40 2006 @@ -1,9 +1,11 @@ import autopath from pypy.translator.translator import TranslationContext +from pypy import conftest +from py.test import raises """ This is a simple approach to support building extension moduels. -Tnbe key idea is to provide a mechanism to record certain objects +The key idea is to provide a mechanism to record certain objects and types to be recognized as SomeObject, to be created using imports without trying to further investigate them. @@ -20,9 +22,10 @@ # use the first type only for the tests spec = spec[0] argstypelist.append(spec) - return argstypelist + missing = [object] * (func.func_code.co_argcount - len(argstypelist)) + return missing + argstypelist -def getcompiled(func, view=False, inline_threshold=1, use_boehm=False): +def getcompiled(func, view=conftest.option.view, inline_threshold=1, use_boehm=False): from pypy.translator.translator import TranslationContext from pypy.translator.backendopt.all import backend_optimizations @@ -48,9 +51,19 @@ t.viewcg() return getattr(cbuilder.import_module(), func.__name__) -def example_long(arg=int): +def example_int_long(arg=int): + return long(arg+42) + +def example_obj_long(arg): return long(arg+42) def test_long(): - f = getcompiled(example_long) - assert example_long(10) == f(10) + f = getcompiled(example_int_long) + assert example_int_long(10) == f(10) + g = getcompiled(example_obj_long) + assert example_obj_long(10) == f(10) + bigval = 123456789012345l + assert raises(OverflowError, f, bigval) + assert g(bigval) == example_obj_long(bigval) + + \ No newline at end of file From goden at codespeak.net Mon Mar 13 06:42:05 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Mon, 13 Mar 2006 06:42:05 +0100 (CET) Subject: [pypy-svn] r24281 - in pypy/dist/pypy: rpython/rctypes rpython/rctypes/test translator/c Message-ID: <20060313054205.4F252100C3@code0.codespeak.net> Author: goden Date: Mon Mar 13 06:41:58 2006 New Revision: 24281 Modified: pypy/dist/pypy/rpython/rctypes/rarray.py pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/dist/pypy/rpython/rctypes/test/test_rarray.py pypy/dist/pypy/translator/c/funcgen.py Log: - rctypes: added a conversion from PrimitiveRepr to IntegerRepr to handle the implicit conversion that occurs when assigning ctypes' array items with ctypes' primitives. fixed the rarray low-level representation, getitem, and setitem for use with boxed ctypes primitives. re-enabled two fixed test_rarray tests and added another to test compiling. added a check in pypy.translator.c.funcgen.OP_MALLOC_VARSIZE() to check the 'nolength' hint and avoid setting the length of the rctypes translated arrays when malloc'd. Modified: pypy/dist/pypy/rpython/rctypes/rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/rarray.py Mon Mar 13 06:41:58 2006 @@ -15,11 +15,18 @@ self.length = type._length_ entry = extregistry.lookup_type(item_ctype) - self.r_item = entry.get_repr(rtyper, item_ctype) + # XXX: goden: So at this point item_ctype is a ctypes object. + # I *think* we need to send a "SomeCTypesObject" box + # to get the PrimitiveRepr instead of the ctypes object + # itself. + self.r_item = entry.get_repr(rtyper, SomeCTypesObject(item_ctype, + SomeCTypesObject.OWNSMEMORY)) + # Array elements are of the low-level type (Signed, etc) and not + # of the boxed low level type (Ptr(GcStruct(...))) self.lowleveltype = lltype.Ptr( lltype.GcStruct( "CtypesGcArray_%s" % type.__name__, - ( "c_data", lltype.Array(self.r_item.lowleveltype, + ( "c_data", lltype.Array(self.r_item.ll_type, hints={"nolength": True}) ) ) @@ -28,7 +35,7 @@ class __extend__(pairtype(ArrayRepr, IntegerRepr)): def rtype_setitem((r_array, r_int), hop): v_array, v_index, v_item = hop.inputargs(r_array, lltype.Signed, - r_array.r_item) + r_array.r_item.ll_type) inputargs = [v_array, hop.inputconst(lltype.Void, "c_data")] v_c_data = hop.genop('getsubstruct', inputargs, @@ -43,7 +50,7 @@ inputargs, lltype.Ptr(r_array.lowleveltype.TO.c_data) ) return hop.genop('getarrayitem', [v_c_data, v_index], - r_array.r_item.lowleveltype) + r_array.r_item.ll_type) def arraytype_specialize_call(hop): r_array = hop.r_result Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/rprimitive.py Mon Mar 13 06:41:58 2006 @@ -82,6 +82,15 @@ self.ll_type) self.setfield(hop.llops, v_primitive, v_value) +# need to extend primitive repr to implement convert_from_to() for various +# conversions, firstly the conversion from c_long() to Signed + +class __extend__(pairtype(PrimitiveRepr, IntegerRepr)): + def convert_from_to((r_from, r_to), v, llops): + assert r_from.ll_type == r_to.lowleveltype + + return r_from.getfield(llops, v) + def primitive_specialize_call(hop): r_primitive = hop.r_result c1 = hop.inputconst(lltype.Void, r_primitive.lowleveltype.TO) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rarray.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Mon Mar 13 06:41:58 2006 @@ -6,6 +6,7 @@ from pypy.annotation.annrpython import RPythonAnnotator from pypy.translator.translator import TranslationContext from pypy import conftest +from pypy.translator.c.test.test_genc import compile import sys from pypy.rpython.test.test_llinterp import interpret @@ -127,7 +128,7 @@ py.test.raises(IndexError, "s = a.build_types(access_with_invalid_negative_index,[])") class Test_specialization: - def x_test_specialize_array(self): + def test_specialize_array(self): def create_array(): return c_int_10() @@ -138,12 +139,26 @@ py.test.raises(IndexError, "c_data[10]") py.test.raises(TypeError, "len(c_data)") - def x_test_specialize_array_access(self): + def test_specialize_array_access(self): def access_array(): my_array = c_int_10() my_array[0] = 1 + my_array[1] = c_int(1) return my_array[0] res = interpret(access_array, []) assert res == 1 + +class Test_compilation: + def test_compile_array_access(self): + def access_array(): + my_array = c_int_10() + my_array[0] = 1 + my_array[1] = c_int(2) + + return my_array[1] + + fn = compile(access_array, []) + + assert fn() == 2 Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Mon Mar 13 06:41:58 2006 @@ -563,7 +563,10 @@ elength, itemtype) result += self.gcpolicy.zero_malloc(TYPE, esize, eresult, err) - result += '\n%s->%s = %s;' % (eresult, lenfld, elength) + + # ctypes Arrays have no length field + if not VARPART._hints.get('nolength', False): + result += '\n%s->%s = %s;' % (eresult, lenfld, elength) return result def OP_FLAVORED_MALLOC(self, op, err): From pedronis at codespeak.net Mon Mar 13 11:52:59 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Mar 2006 11:52:59 +0100 (CET) Subject: [pypy-svn] r24284 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20060313105259.A4EF61009B@code0.codespeak.net> Author: pedronis Date: Mon Mar 13 11:52:58 2006 New Revision: 24284 Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py Log: preserve solidity Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Mon Mar 13 11:52:58 2006 @@ -574,11 +574,11 @@ raise TypeError, "can only cast pointers to other pointers" return ptr._cast_to(PTRTYPE) -def _expose(val): +def _expose(val, solid=False): """XXX A nice docstring here""" T = typeOf(val) if isinstance(T, ContainerType): - val = _ptr(Ptr(T), val) + val = _ptr(Ptr(T), val, solid=solid) return val def parentlink(container): @@ -677,7 +677,7 @@ if isinstance(self._T, Struct): if field_name in self._T._flds: o = getattr(self._obj, field_name) - return _expose(o) + return _expose(o, self._solid) if isinstance(self._T, ContainerType): adtmeth = self._T._adtmeths.get(field_name) if adtmeth is not None: @@ -719,7 +719,7 @@ if not (0 <= i < len(self._obj.items)): raise IndexError("array index out of bounds") o = self._obj.items[i] - return _expose(o) + return _expose(o, self._solid) raise TypeError("%r instance is not an array" % (self._T,)) def __setitem__(self, i, val): @@ -782,7 +782,7 @@ while down_or_up: p = getattr(p, typeOf(p).TO._names[0]) down_or_up -= 1 - return _ptr(PTRTYPE, p._obj) + return _ptr(PTRTYPE, p._obj, solid=self._solid) u = -down_or_up struc = self._obj while u: @@ -796,7 +796,7 @@ u -= 1 if PARENTTYPE != PTRTYPE.TO: raise TypeError("widening %r inside %r instead of %r" % (CURTYPE, PARENTTYPE, PTRTYPE.TO)) - return _ptr(PTRTYPE, struc) + return _ptr(PTRTYPE, struc, solid=self._solid) def _cast_to_int(self): obj = self._obj From nik at codespeak.net Mon Mar 13 12:30:56 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 12:30:56 +0100 (CET) Subject: [pypy-svn] r24285 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060313113056.A469C100A8@code0.codespeak.net> Author: nik Date: Mon Mar 13 12:30:55 2006 New Revision: 24285 Added: pypy/dist/pypy/translator/squeak/test/runtest.py Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: moved testing squeak gateway into its own module, for use by arbitrary tests. Added: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Mon Mar 13 12:30:55 2006 @@ -0,0 +1,83 @@ +import os +import py +from pypy.tool.udir import udir +from pypy.translator.squeak.gensqueak import GenSqueak, Selector +from pypy.translator.translator import TranslationContext +from pypy import conftest + +def compile_function(func, annotation=[]): + return SqueakFunction(func, annotation) + + +# For now use pipes to communicate with squeak. This is very flaky +# and only works for posix systems. At some later point we'll +# probably need a socket based solution for this. +startup_script = """ +| stdout src selector result arguments arg i | +src := Smalltalk getSystemAttribute: 3. +FileStream fileIn: src. +selector := (Smalltalk getSystemAttribute: 4) asSymbol. +arguments := OrderedCollection new. +i := 4. +[(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil] + whileTrue: [arguments add: arg asInteger]. + +PyConstants setupConstants. +result := (PyFunctions perform: selector withArguments: arguments asArray). +stdout := StandardFileStream fileNamed: '/dev/stdout'. +stdout nextPutAll: result asString. +Smalltalk snapshot: false andQuit: true. +""" + +class SqueakFunction: + + def __init__(self, func, annotation): + self._func = func + self._gen = self._build(func, annotation) + + def _build(self, func, annotation): + try: + func = func.im_func + except AttributeError: + pass + t = TranslationContext() + t.buildannotator().build_types(func, annotation) + t.buildrtyper(type_system="ootype").specialize() + if conftest.option.view: + t.viewcg() + return GenSqueak(udir, t) + + def _write_startup(self): + startup_st = udir.join("startup.st") + try: + # Erm, py.path.local has no "exists" method? + startup_st.stat() + except py.error.ENOENT: + f = startup_st.open("w") + f.write(startup_script) + f.close() + return startup_st + + def __call__(self, *args): + # NB: only integers arguments are supported currently + try: + import posix + except ImportError: + py.test.skip("Squeak tests only work on Unix right now.") + try: + py.path.local.sysfind("squeak") + except py.error.ENOENT: + py.test.skip("Squeak is not on your path.") + if os.getenv("SQUEAK_IMAGE") is None: + py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " + "variable to point to an image.") + startup_st = self._write_startup() + cmd = 'squeak -headless -- %s %s "%s" %s' \ + % (startup_st, udir.join(self._gen.filename), + Selector(self._func.__name__, len(args)).symbol(), + " ".join(['"%s"' % a for a in args])) + squeak_process = os.popen(cmd) + result = squeak_process.read() + assert squeak_process.close() is None # exit status was 0 + return result + Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Mon Mar 13 12:30:55 2006 @@ -1,10 +1,8 @@ import os import py -from pypy.tool.udir import udir from pypy.translator.test import snippet -from pypy.translator.squeak.gensqueak import GenSqueak, Selector, camel_case -from pypy.translator.translator import TranslationContext -from pypy import conftest +from pypy.translator.squeak.gensqueak import Selector, camel_case +from pypy.translator.squeak.test.runtest import compile_function def looping(i, j): @@ -13,89 +11,28 @@ while j > 0: j -= 1 -def build_sqfunc(func, args=[]): - try: func = func.im_func - except AttributeError: pass - t = TranslationContext() - t.buildannotator().build_types(func, args) - if conftest.option.view: - t.viewcg() - t.buildrtyper(type_system="ootype").specialize() - if conftest.option.view: - t.viewcg() - return GenSqueak(udir, t) - class TestSqueakTrans: def test_simple_func(self): - build_sqfunc(snippet.simple_func, [int]) + compile_function(snippet.simple_func, [int]) def test_if_then_else(self): - build_sqfunc(snippet.if_then_else, [bool, int, int]) + compile_function(snippet.if_then_else, [bool, int, int]) def test_my_gcd(self): - build_sqfunc(snippet.my_gcd, [int, int]) + compile_function(snippet.my_gcd, [int, int]) def test_looping(self): - build_sqfunc(looping, [int, int]) - + compile_function(looping, [int, int]) -# For now use pipes to communicate with squeak. This is very flaky -# and only works for posix systems. At some later point we'll -# probably need a socket based solution for this. -startup_script = """ -| stdout src selector result arguments arg i | -src := Smalltalk getSystemAttribute: 3. -FileStream fileIn: src. -selector := (Smalltalk getSystemAttribute: 4) asSymbol. -arguments := OrderedCollection new. -i := 4. -[(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil] - whileTrue: [arguments add: arg asInteger]. - -PyConstants setupConstants. -result := (PyFunctions perform: selector withArguments: arguments asArray). -stdout := StandardFileStream fileNamed: '/dev/stdout'. -stdout nextPutAll: result asString. -Smalltalk snapshot: false andQuit: true. -""" class TestGenSqueak: - def setup_class(self): - self.startup_st = udir.join("startup.st") - f = self.startup_st.open("w") - f.write(startup_script) - f.close() - - def run_on_squeak(self, function, *args): - # NB: only integers arguments are supported currently - try: - import posix - except ImportError: - py.test.skip("Squeak tests only work on Unix right now.") - try: - py.path.local.sysfind("squeak") - except py.error.ENOENT: - py.test.skip("Squeak is not on your path.") - if os.getenv("SQUEAK_IMAGE") is None: - py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " - "variable to point to an image.") - arg_types = [type(arg) for arg in args] - gen_squeak = build_sqfunc(function, arg_types) - cmd = 'squeak -headless -- %s %s "%s" %s' \ - % (self.startup_st, udir.join(gen_squeak.filename), - Selector(function.__name__, len(args)).symbol(), - " ".join(['"%s"' % a for a in args])) - squeak_process = os.popen(cmd) - result = squeak_process.read() - assert squeak_process.close() is None # exit status was 0 - return result - def test_theanswer(self): def theanswer(): return 42 - assert self.run_on_squeak(theanswer) == "42" + fn = compile_function(theanswer) + assert fn() == "42" def test_simplemethod(self): class A: @@ -103,12 +40,14 @@ return 42 def simplemethod(): return A().m() - assert self.run_on_squeak(simplemethod) == "42" + fn = compile_function(simplemethod) + assert fn() == "42" def test_argfunction(self): def function(i, j=2): return i + j - assert self.run_on_squeak(function, 1, 3) == "4" + fn = compile_function(function, [int, int]) + assert fn(1, 3) == "4" def test_argmethod(self): class A: @@ -116,7 +55,8 @@ return i + j + h def simplemethod(i): return A().m(i, j=3) - assert self.run_on_squeak(simplemethod, 1) == "6" + fn = compile_function(simplemethod, [int]) + assert fn(1) == "6" def test_nameclash_classes(self): from pypy.translator.squeak.test.support import A as A2 @@ -124,7 +64,8 @@ def m(self, i): return 2 + i def f(): return A().m(0) + A2().m(0) - assert self.run_on_squeak(f) == "3" + fn = compile_function(f) + assert fn() == "3" def test_nameclash_classes_mean(self): class A: @@ -134,7 +75,8 @@ def m(self, i): return 2 + i def f(): return A().m(0) + A2().m(0) - assert self.run_on_squeak(f) == "3" + fn = compile_function(f) + assert fn() == "3" def test_nameclash_camel_case(self): class ASomething: @@ -144,7 +86,8 @@ def f(): x = ASomething().m(0) + A_Something().m(0) return x + ASomething().m(0) + A_Something().m(0) - assert self.run_on_squeak(f) == "6" + fn = compile_function(f) + assert fn() == "6" def test_nameclash_functions(self): from pypy.translator.squeak.test.support import f as f2 @@ -152,7 +95,8 @@ return i + 2 def g(): return f(0) + f2(0) - assert self.run_on_squeak(g) == "3" + fn = compile_function(g) + assert fn() == "3" def test_direct_call(self): def h(i): @@ -161,7 +105,8 @@ return i + 1 def f(i): return h(i) + g(i) - assert self.run_on_squeak(f, 1) == "5" + fn = compile_function(f, [int]) + assert fn(1) == "5" def test_getfield_setfield(self): class A: @@ -176,7 +121,8 @@ a.i_var = 3 a.inc() return i + a.i_var - assert self.run_on_squeak(f, 2) == "6" + fn = compile_function(f, [int]) + assert fn(2) == "6" def test_classvars(self): class A: i = 1 @@ -190,8 +136,9 @@ def f(i): c = pick(i) return c.i - assert self.run_on_squeak(f, 1) == "1" - assert self.run_on_squeak(f, 2) == "2" + fn = compile_function(f, [int]) + assert fn(1) == "1" + assert fn(2) == "2" class TestSelector: From nik at codespeak.net Mon Mar 13 12:49:25 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 12:49:25 +0100 (CET) Subject: [pypy-svn] r24286 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060313114925.6EE33100B9@code0.codespeak.net> Author: nik Date: Mon Mar 13 12:49:24 2006 New Revision: 24286 Added: pypy/dist/pypy/translator/squeak/conftest.py Modified: pypy/dist/pypy/translator/squeak/test/runtest.py Log: add a py.test option to not run squeak headless, for convenience when debugging generated squeak code. Added: pypy/dist/pypy/translator/squeak/conftest.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/conftest.py Mon Mar 13 12:49:24 2006 @@ -0,0 +1,8 @@ +import py + +Option = py.test.Config.Option + +option = py.test.Config.addoptions("pypy-squeak options", + Option('--showsqueak', action="store_true", dest="showsqueak", + default=False, help="don't run squeak headless, for debugging"), + ) Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Mon Mar 13 12:49:24 2006 @@ -72,8 +72,11 @@ py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment " "variable to point to an image.") startup_st = self._write_startup() - cmd = 'squeak -headless -- %s %s "%s" %s' \ - % (startup_st, udir.join(self._gen.filename), + options = "-headless" + if conftest.option.showsqueak: + options = "" + cmd = 'squeak %s -- %s %s "%s" %s' \ + % (options, startup_st, udir.join(self._gen.filename), Selector(self._func.__name__, len(args)).symbol(), " ".join(['"%s"' % a for a in args])) squeak_process = os.popen(cmd) From auc at codespeak.net Mon Mar 13 13:19:34 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 13 Mar 2006 13:19:34 +0100 (CET) Subject: [pypy-svn] r24287 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060313121934.EBBC7100C6@code0.codespeak.net> Author: auc Date: Mon Mar 13 13:19:33 2006 New Revision: 24287 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py Log: removed locks Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Mon Mar 13 13:19:33 2006 @@ -72,7 +72,6 @@ # we have to enforce only one distributor # thread running in one space at the same time - _nb_choices = 0 _id_count = 0 def __init__(self, problem, parent=None): @@ -81,8 +80,6 @@ self.status = Unknown # consistency-preserving stuff self.in_transaction = False - self.bind_lock = RLock() - self.var_lock = RLock() self.distributor = DefaultDistributor(self) # mapping from domains to variables self.doms = {} @@ -265,13 +262,9 @@ def var(self, name): """creates a single assignment variable of name name and puts it into the store""" - self.var_lock.acquire() - try: - v = CsVar(name, self) - self.add_unbound(v) - return v - finally: - self.var_lock.release() + v = CsVar(name, self) + self.add_unbound(v) + return v def make_vars(self, *names): variables = [] @@ -486,30 +479,26 @@ # where binding several times to compatible # values is allowed provided no information is # removed (this last condition remains to be checked) - self.bind_lock.acquire() - try: - assert(isinstance(var, CsVar) and (var in self.vars)) - if var == val: - return - if _both_are_vars(var, val): - if _both_are_bound(var, val): - if _unifiable(var, val): - return # XXX check corrrectness - raise UnificationFailure(var, val) - if var._is_bound(): # 2b. var is bound, not var - self.bind(val, var) - elif val._is_bound(): # 2a.var is bound, not val - self._bind(var.val, val.val) - else: # 1. both are unbound - self._alias(var, val) - else: # 3. val is really a value - if var._is_bound(): - if _unifiable(var.val, val): - return # XXX check correctness - raise UnificationFailure(var, val) - self._bind(var.val, val) - finally: - self.bind_lock.release() + assert(isinstance(var, CsVar) and (var in self.vars)) + if var == val: + return + if _both_are_vars(var, val): + if _both_are_bound(var, val): + if _unifiable(var, val): + return # XXX check corrrectness + raise UnificationFailure(var, val) + if var._is_bound(): # 2b. var is bound, not var + self.bind(val, var) + elif val._is_bound(): # 2a.var is bound, not val + self._bind(var.val, val.val) + else: # 1. both are unbound + self._alias(var, val) + else: # 3. val is really a value + if var._is_bound(): + if _unifiable(var.val, val): + return # XXX check correctness + raise UnificationFailure(var, val) + self._bind(var.val, val) def _bind(self, eqs, val): # print "variable - value binding : %s %s" % (eqs, val) Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Mon Mar 13 13:19:33 2006 @@ -122,11 +122,7 @@ def nb_subdomains(self): """See AbstractDistributor""" - try: - self.cs.var_lock.acquire() - self.__to_split = self.findSmallestDomain() - finally: - self.cs.var_lock.release() + self.__to_split = self.findSmallestDomain() if self.nb_subspaces: return min(self.nb_subspaces, self.cs.dom(self.__to_split).size()) From auc at codespeak.net Mon Mar 13 13:40:06 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 13 Mar 2006 13:40:06 +0100 (CET) Subject: [pypy-svn] r24288 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060313124006.23CF5100CB@code0.codespeak.net> Author: auc Date: Mon Mar 13 13:40:04 2006 New Revision: 24288 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: dead code removal Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Mon Mar 13 13:40:04 2006 @@ -192,9 +192,6 @@ return True return False - def top_level(self): - return self.parent is None - def _notify(self, event): self.event_set.add(event) @@ -299,24 +296,14 @@ def is_bound(self, var): """check wether a var is locally bound""" - if self.top_level(): - return var.is_bound() - return len(self.dom(var)) == 1 + return var.is_bound() or len(self.dom(var)) == 1 def val(self, var): """return the local binding without blocking""" - if self.top_level(): # the real thing - return var.val if self.is_bound(var): # the speculative val return self.dom(var)[0] return NoValue - def _del_var(self, var): - """purely private stuff, use at your own perils""" - self.vars.remove(var) - if self.doms.has_key(var): - del self.doms[var] - #-- Domains ----------------------------- def set_dom(self, var, dom): @@ -423,19 +410,6 @@ if const in affected_constraints: affected_constraints.remove(const) - def _compute_dependant_vars(self, constraint, varset, - constset): - if constraint in constset: return - constset.add(constraint) - for var in constraint.affected_variables(): - varset.add(var) - dep_consts = self.var_const_map[var] - for const in dep_consts: - if const in constset: - continue - self._compute_dependant_vars(const, varset, - constset) - def _compatible_domains(self, var, eqs): """check that the domain of var is compatible with the domains of the vars in the eqs @@ -660,44 +634,3 @@ def _both_are_bound(v1, v2): return v1._is_bound() and v2._is_bound() -def diff_list(l1, l2): - diff = {} - idx = 0 - for e1, e2 in zip(l1, l2): - if e1 != e2: diff[idx] = (e1, e2) - idx += 1 - return diff - -def backup_domains(space): - print "-- backup of domains (%s) --" % space.id - doms = [] - for v, d in space.doms.items(): - if d != NoDom: - doms.append((v, len(d))) - doms.sort() - print " (", [elt[1] for elt in doms], ")" - return doms - -def print_quick_diff(space, domain_history): - ldh = len(domain_history) - if ldh > 0: - print "history size (%s) : %s" % (space.id, ldh) - last = domain_history[-1] - else: - curr = [(item[0], len(item[1].get_values())) - for item in space.doms.items() - if item[1] != NoDom] - curr.sort() - print "(diff -- v : d 0 (%s)" % space.id - for l in curr: - print ' '*6, '%s : %2d' % (l[0], l[1]) - print " --)" - return - curr = [(item[0], len(item[1].get_values())) - for item in space.doms.items() - if item[1] != NoDom] - curr.sort() - print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, space.id) - for l1, l2 in zip(last, curr): - print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1]) - print " --)" Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Mon Mar 13 13:40:04 2006 @@ -327,25 +327,6 @@ assert sp.dom(y) == c.FiniteDomain([2]) assert sp.dom(z) == c.FiniteDomain([3]) - def test_compute_dependant_vars(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.set_dom(x, c.FiniteDomain([1, 2, 5])) - sp.set_dom(y, c.FiniteDomain([2, 3])) - sp.set_dom(z, c.FiniteDomain([3, 4])) - sp.set_dom(w, c.FiniteDomain([1, 4, 5])) - k1 = c.Expression(sp, [x, y, z], 'x == y + z') - k2 = c.Expression(sp, [z, w], 'z < w') - sp.add_expression(k1) - sp.add_expression(k2) - varset = set() - constset = set() - sp._compute_dependant_vars(k1, varset, constset) - assert varset == set([x, y, z, w]) - assert constset == set([k1, k2]) - - #-- computation spaces ------------------------------- import strategies From auc at codespeak.net Mon Mar 13 13:50:11 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 13 Mar 2006 13:50:11 +0100 (CET) Subject: [pypy-svn] r24289 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060313125011.4A7ED100CB@code0.codespeak.net> Author: auc Date: Mon Mar 13 13:50:10 2006 New Revision: 24289 Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py Log: cleanup Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Mon Mar 13 13:50:10 2006 @@ -66,9 +66,6 @@ self.val = val def get(self): - """Make threads wait on the variable - being bound in the top-level space - """ try: self._value_condition.acquire() while not self.is_bound(): @@ -80,21 +77,6 @@ return self.val finally: self._value_condition.release() - - - def reset(self): - self._value_condition.acquire() - self._val = NoValue - self._value_condition.release() - - -class StreamVar(object): - def __init__(self): - self.var = SimpleVar() - - def bind( self, val ): - newvar = SimpleVar() - self.var.bind( (val, newvar) ) class CsVar(SimpleVar): From auc at codespeak.net Mon Mar 13 13:56:22 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 13 Mar 2006 13:56:22 +0100 (CET) Subject: [pypy-svn] r24290 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060313125622.CEB76100CB@code0.codespeak.net> Author: auc Date: Mon Mar 13 13:56:21 2006 New Revision: 24290 Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_variable.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: api change (get->wait) Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Mon Mar 13 13:56:21 2006 @@ -238,7 +238,7 @@ start_time = time.time() def wait_on_unbound(thread, var, start_time): - thread.val = var.get() + thread.val = var.wait() thread.waited = time.time() - start_time x = sp.var('x') Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Mon Mar 13 13:56:21 2006 @@ -25,7 +25,7 @@ self.var = var def run(self): - val = self.var.get() + val = self.var.wait() class NConsumer(Thread): @@ -33,7 +33,7 @@ self.vars = vars_ def run(self): - val = [var.get() for var in self.vars] + val = [var.wait() for var in self.vars] def newspace(): return space.ComputationSpace(dummy_problem) @@ -54,7 +54,7 @@ def test_dataflow(self): def fun(thread, var): thread.state = 1 - v = var.get() + v = var.wait() thread.state = v x = v.SimpleVar() @@ -69,7 +69,7 @@ def test_stream(self): def consummer(thread, S): - v = S.get() + v = S.wait() if v: thread.res += v[0] consummer(thread, v[1]) @@ -168,7 +168,7 @@ end""" sp = newspace() print "GENERATOR waits on Xs" - X_Xr = Xs.get() # destructure Xs + X_Xr = Xs.wait() # destructure Xs if X_Xr == None: return X = X_Xr[0] # ... into X X.bind(n) # bind X to n @@ -192,7 +192,7 @@ Xr = sp.var('Xr') print "CLIENT binds Xs to X|Xr" Xs.bind((X, Xr)) - x = X.get() # wait on the value of X + x = X.wait() # wait on the value of X print "CLIENT got", x dsum(thread, Xr, a+x, limit-1) else: @@ -209,7 +209,7 @@ else {Sum Xs A} end end""" - X_Xr = Xs.get() + X_Xr = Xs.wait() if X_Xr == EOL: thread.result = a return @@ -301,11 +301,11 @@ end """ sp = newspace() - Y_Yr = Ys.get() # destructure Ys + Y_Yr = Ys.wait() # destructure Ys if Y_Yr != None: Y, Yr = Y_Yr - X, Xr = Xs.get() - Y.bind(X.get()) + X, Xr = Xs.wait() + Y.bind(X.wait()) End2 = sp.var('End2') X_ = sp.var('X_') End.bind((X_, End2)) Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Mon Mar 13 13:56:21 2006 @@ -65,7 +65,7 @@ def bind(self, val): self.val = val - def get(self): + def wait(self): try: self._value_condition.acquire() while not self.is_bound(): From nik at codespeak.net Mon Mar 13 14:57:47 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 14:57:47 +0100 (CET) Subject: [pypy-svn] r24301 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060313135747.5A9F2100D2@code0.codespeak.net> Author: nik Date: Mon Mar 13 14:57:45 2006 New Revision: 24301 Added: pypy/dist/pypy/translator/squeak/test/test_llops.py Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/runtest.py Log: make some tests for low-level integer operations pass. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Mon Mar 13 14:57:45 2006 @@ -245,7 +245,10 @@ 'classof': Selector('class', 0), 'sameAs': Selector('yourself', 0), 'intAdd:': Selector('+', 1), + 'intSub:': Selector('-', 1), 'intEq:': Selector('=', 1), + 'intMul:': Selector('*', 1), + 'intFloordiv:': Selector('//', 1), } def render_body(self, startblock): Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Mon Mar 13 14:57:45 2006 @@ -43,6 +43,7 @@ t = TranslationContext() t.buildannotator().build_types(func, annotation) t.buildrtyper(type_system="ootype").specialize() + self.graph = t.graphs[0] if conftest.option.view: t.viewcg() return GenSqueak(udir, t) Added: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 13 14:57:45 2006 @@ -0,0 +1,38 @@ +from pypy.translator.squeak.test.runtest import compile_function + +def optest(testcase): + opname = testcase[0] + opstring = testcase[1] + args = testcase[2:] + annotation = [type(a) for a in args] + func = opfunction(opstring, args) + sqfunc = compile_function(func, annotation) + + # Make sure we actually test what we intend to test + found_llop = False + for op in sqfunc.graph.startblock.operations: + if op.opname == opname: + found_llop = True + break + assert found_llop + + assert sqfunc(*args) == str(func(*args)) + +def opfunction(opstring, annotation): + exec """def fn(v1, v2): + return v1 %s v2""" % opstring + return fn + +def test_intoperations(): + tests = [ + # XXX Must handle overflows for all integer ops + ("int_add", "+", 1, 2), + ("int_sub", "-", 1, 3), + ("int_mul", "*", 2, 3), + # XXX how to produce int_div and int_truediv? + ("int_floordiv", "//", 7, 3), + ("int_floordiv", "//", -7, 3), + ] + for t in tests: + yield optest, t + From nik at codespeak.net Mon Mar 13 16:35:36 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 16:35:36 +0100 (CET) Subject: [pypy-svn] r24308 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060313153536.B96CF100D7@code0.codespeak.net> Author: nik Date: Mon Mar 13 16:35:34 2006 New Revision: 24308 Modified: pypy/dist/pypy/translator/squeak/test/runtest.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: extend squeak gateway to handle bare graphs too, not just functions. handcraft graphs for llop tests. Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Mon Mar 13 16:35:34 2006 @@ -5,8 +5,8 @@ from pypy.translator.translator import TranslationContext from pypy import conftest -def compile_function(func, annotation=[]): - return SqueakFunction(func, annotation) +def compile_function(func, annotation=[], graph=None): + return SqueakFunction(func, annotation, graph) # For now use pipes to communicate with squeak. This is very flaky @@ -31,17 +31,24 @@ class SqueakFunction: - def __init__(self, func, annotation): + def __init__(self, func, annotation, graph=None): self._func = func - self._gen = self._build(func, annotation) + self._gen = self._build(func, annotation, graph) - def _build(self, func, annotation): + def _build(self, func, annotation, graph=None): try: func = func.im_func except AttributeError: pass t = TranslationContext() - t.buildannotator().build_types(func, annotation) + if graph is not None: + graph.func = func + ann = t.buildannotator() + inputcells = [ann.typeannotation(a) for a in annotation] + ann.build_graph_types(graph, inputcells) + t.graphs.insert(0, graph) + else: + t.buildannotator().build_types(func, annotation) t.buildrtyper(type_system="ootype").specialize() self.graph = t.graphs[0] if conftest.option.view: Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 13 16:35:34 2006 @@ -1,37 +1,47 @@ from pypy.translator.squeak.test.runtest import compile_function +from pypy.translator.translator import TranslationContext +from pypy.objspace.flow.operation import FunctionByName +from pypy.objspace.flow.model import * def optest(testcase): opname = testcase[0] - opstring = testcase[1] + llopname = testcase[1] args = testcase[2:] + + # This code adpated from translator/c/test/test_operation.py + inputvars = [Variable() for _ in args] + block = Block(inputvars) + op = SpaceOperation(opname, inputvars, Variable()) + block.operations.append(op) + graph = FunctionGraph('operationdummy', block) + block.closeblock(Link([op.result], graph.returnblock)) + annotation = [type(a) for a in args] - func = opfunction(opstring, args) - sqfunc = compile_function(func, annotation) + sqfunc = compile_function(operationdummy, annotation, graph) # Make sure we actually test what we intend to test found_llop = False for op in sqfunc.graph.startblock.operations: - if op.opname == opname: + if op.opname == llopname: found_llop = True break assert found_llop - assert sqfunc(*args) == str(func(*args)) + expected_result = FunctionByName[opname](*args) + assert sqfunc(*args) == str(expected_result) -def opfunction(opstring, annotation): - exec """def fn(v1, v2): - return v1 %s v2""" % opstring - return fn +def operationdummy(v1, v2): + pass def test_intoperations(): tests = [ # XXX Must handle overflows for all integer ops - ("int_add", "+", 1, 2), - ("int_sub", "-", 1, 3), - ("int_mul", "*", 2, 3), - # XXX how to produce int_div and int_truediv? - ("int_floordiv", "//", 7, 3), - ("int_floordiv", "//", -7, 3), + ("add", "int_add", 1, 2), + ("sub", "int_sub", 1, 3), + ("mul", "int_mul", 2, 3), + # I think int_div and int_truediv are currently never generated + ("floordiv", "int_floordiv", 7, 3), + ("floordiv", "int_floordiv", -7, 3), ] for t in tests: yield optest, t From pedronis at codespeak.net Mon Mar 13 17:11:27 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Mar 2006 17:11:27 +0100 (CET) Subject: [pypy-svn] r24311 - in pypy/dist/pypy/rpython/lltypesystem: . test Message-ID: <20060313161127.555A5100DD@code0.codespeak.net> Author: pedronis Date: Mon Mar 13 17:11:25 2006 New Revision: 24311 Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py Log: allow cast_pointer between identical array types. (It was disallowed before, now with the jit code we are emitting much more generic code) Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Mon Mar 13 17:11:25 2006 @@ -555,6 +555,8 @@ if CURTYPE._needsgc() != PTRTYPE._needsgc(): raise TypeError("cast_pointer() cannot change the gc status: %s to %s" % (CURTYPE, PTRTYPE)) + if CURTYPE == PTRTYPE: + return 0 if (not isinstance(CURTYPE.TO, Struct) or not isinstance(PTRTYPE.TO, Struct)): raise InvalidCast(CURTYPE, PTRTYPE) Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py Mon Mar 13 17:11:25 2006 @@ -507,6 +507,12 @@ res = cast_primitive(TGT, orig_val) assert typeOf(res) == TGT assert res == expect + +def test_cast_identical_array_ptr_types(): + A = GcArray(Signed) + PA = Ptr(A) + a = malloc(A, 2) + assert cast_pointer(PA, a) == a def test_array_with_no_length(): A = GcArray(Signed, hints={'nolength': True}) From pedronis at codespeak.net Mon Mar 13 17:12:53 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Mar 2006 17:12:53 +0100 (CET) Subject: [pypy-svn] r24312 - in pypy/dist/pypy/jit: . test Message-ID: <20060313161253.6C2C2100DE@code0.codespeak.net> Author: pedronis Date: Mon Mar 13 17:12:46 2006 New Revision: 24312 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: proper getarrayitem support Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Mon Mar 13 17:12:46 2006 @@ -118,6 +118,25 @@ [v_jitstate, c_fielddesc, v_argbox, c_fieldname, c_resulttype], ts.s_RedBox) + def translate_op_getarrayitem(self, hop): + ts = self.timeshifter + PTRTYPE = originalconcretetype(hop.args_s[0]) + RESTYPE = originalconcretetype(hop.s_result) + v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), + self.getredrepr(lltype.Signed)) + fielddesc = rtimeshift.make_fielddesc(PTRTYPE, '-') + c_fielddesc = inputconst(lltype.Void, fielddesc) + s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) + gv_resulttype = rgenop.constTYPE(RESTYPE) + c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) + v_jitstate = hop.llops.getjitstate() + s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getarrayitem, + [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox, s_CONSTORVAR], + [v_jitstate, c_fielddesc, v_argbox, v_index, c_resulttype], + ts.s_RedBox) + + class HintLowLevelOpList(LowLevelOpList): """Warning: the HintLowLevelOpList's rtyper is the *original* Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Mon Mar 13 17:12:46 2006 @@ -208,6 +208,21 @@ gv_resulttype) return VarRedBox(genvar) + +def ll_generate_getarrayitem(jitstate, fielddesc, argbox, + indexbox, gv_resulttype): + if (fielddesc.immutable and + isinstance(argbox, ConstRedBox) and isinstance(indexbox, ConstRedBox)): + res = argbox.ll_getvalue(fielddesc.PTRTYPE)[indexbox.ll_getvalue(lltype.Signed)] + return ConstRedBox.ll_fromvalue(res) + op_args = lltype.malloc(VARLIST.TO, 2) + op_args[0] = argbox.getgenvar() + op_args[1] = indexbox.getgenvar() + genvar = rgenop.genop(jitstate.curblock, 'getarrayitem', op_args, + gv_resulttype) + return VarRedBox(genvar) + + # ____________________________________________________________ # other jitstate/graph level operations Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Mon Mar 13 17:12:46 2006 @@ -268,3 +268,19 @@ insns, res = timeshift(ll_function, [s1], [0]) assert res == 42 assert insns == {} + +def test_simple_array(): + A = lltype.GcArray(lltype.Signed, + hints={'immutable': True}) + def ll_function(a): + return a[0] * a[1] + a1 = lltype.malloc(A, 2) + a1[0] = 6 + a1[1] = 7 + insns, res = timeshift(ll_function, [a1], []) + assert res == 42 + assert insns == {'getarrayitem': 2, + 'int_mul': 1} + insns, res = timeshift(ll_function, [a1], [0]) + assert res == 42 + assert insns == {} From nik at codespeak.net Mon Mar 13 17:54:36 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 17:54:36 +0100 (CET) Subject: [pypy-svn] r24315 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060313165436.83AFC100DE@code0.codespeak.net> Author: nik Date: Mon Mar 13 17:54:34 2006 New Revision: 24315 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: revamping testing of llops again, specializing low-level functions directly (thanks for the hint, pedronis). Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Mon Mar 13 17:54:34 2006 @@ -248,7 +248,9 @@ 'intSub:': Selector('-', 1), 'intEq:': Selector('=', 1), 'intMul:': Selector('*', 1), + 'intDiv:': Selector('//', 1), 'intFloordiv:': Selector('//', 1), + 'intAbs': Selector('abs', 0), } def render_body(self, startblock): Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 13 17:54:34 2006 @@ -1,47 +1,37 @@ from pypy.translator.squeak.test.runtest import compile_function -from pypy.translator.translator import TranslationContext -from pypy.objspace.flow.operation import FunctionByName -from pypy.objspace.flow.model import * +from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem.lltype import Signed +from pypy.rpython.test.test_llinterp import interpret def optest(testcase): - opname = testcase[0] - llopname = testcase[1] + llopname = testcase[0] + RESTYPE = testcase[1] args = testcase[2:] - # This code adpated from translator/c/test/test_operation.py - inputvars = [Variable() for _ in args] - block = Block(inputvars) - op = SpaceOperation(opname, inputvars, Variable()) - block.operations.append(op) - graph = FunctionGraph('operationdummy', block) - block.closeblock(Link([op.result], graph.returnblock)) + llopfunc = getattr(llop, llopname) + arg_signature = ", ".join(["v%s" % n for n in range(len(args))]) + exec """def lloptest(%s): + return llop.%s(%s, %s)""" \ + % (arg_signature, llopname, RESTYPE._name, + arg_signature) annotation = [type(a) for a in args] - sqfunc = compile_function(operationdummy, annotation, graph) - - # Make sure we actually test what we intend to test - found_llop = False - for op in sqfunc.graph.startblock.operations: - if op.opname == llopname: - found_llop = True - break - assert found_llop - - expected_result = FunctionByName[opname](*args) - assert sqfunc(*args) == str(expected_result) - -def operationdummy(v1, v2): - pass + sqfunc = compile_function(lloptest, annotation) + res = interpret(lloptest, args, policy=LowLevelAnnotatorPolicy()) + assert sqfunc(*args) == str(res) def test_intoperations(): tests = [ # XXX Must handle overflows for all integer ops - ("add", "int_add", 1, 2), - ("sub", "int_sub", 1, 3), - ("mul", "int_mul", 2, 3), - # I think int_div and int_truediv are currently never generated - ("floordiv", "int_floordiv", 7, 3), - ("floordiv", "int_floordiv", -7, 3), + ("int_add", Signed, 1, 2), + ("int_sub", Signed, 1, 3), + ("int_mul", Signed, 2, 3), + ("int_div", Signed, 7, 3), + ("int_floordiv", Signed, 7, 3), + ("int_floordiv", Signed, -7, 3), + ("int_abs", Signed, 7), + ("int_abs", Signed, -7), ] for t in tests: yield optest, t From nik at codespeak.net Mon Mar 13 18:25:07 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 18:25:07 +0100 (CET) Subject: [pypy-svn] r24316 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060313172507.4C486100D7@code0.codespeak.net> Author: nik Date: Mon Mar 13 18:25:00 2006 New Revision: 24316 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: implement unary integer llops for squeak (still not caring about overflow/wraparound). Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Mon Mar 13 18:25:00 2006 @@ -133,7 +133,7 @@ self.parts = [camel_case(function_name)] self.arg_count = arg_count self.infix = False - if not self.parts[0].isalnum(): + if len(self.parts[0]) <= 2 and not self.parts[0].isalnum(): # Binary infix selector, e.g. "+" assert arg_count == 1 self.infix = True @@ -244,13 +244,19 @@ 'runtimenew': Selector('new', 0), 'classof': Selector('class', 0), 'sameAs': Selector('yourself', 0), + + # XXX need to handle overflow for all integer ops + 'intAbs': Selector('abs', 0), + 'intIsTrue': Selector('isZero not', 0), + 'intNeg': Selector('negated', 0), + 'intInvert': Selector('bitInvert', 0), # maybe bitInvert32? + 'intAdd:': Selector('+', 1), 'intSub:': Selector('-', 1), 'intEq:': Selector('=', 1), 'intMul:': Selector('*', 1), 'intDiv:': Selector('//', 1), 'intFloordiv:': Selector('//', 1), - 'intAbs': Selector('abs', 0), } def render_body(self, startblock): Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 13 18:25:00 2006 @@ -1,7 +1,7 @@ from pypy.translator.squeak.test.runtest import compile_function from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.lltypesystem.lltype import Signed +from pypy.rpython.lltypesystem.lltype import Signed, Bool from pypy.rpython.test.test_llinterp import interpret def optest(testcase): @@ -18,20 +18,31 @@ annotation = [type(a) for a in args] sqfunc = compile_function(lloptest, annotation) - res = interpret(lloptest, args, policy=LowLevelAnnotatorPolicy()) - assert sqfunc(*args) == str(res) + expected_res = interpret(lloptest, args, policy=LowLevelAnnotatorPolicy()) + res = sqfunc(*args) + assert res == str(res).lower() # lowercasing for booleans def test_intoperations(): tests = [ # XXX Must handle overflows for all integer ops + + # unary + ("int_abs", Signed, 7), + ("int_abs", Signed, -7), + ("int_is_true", Bool, 8), + ("int_is_true", Bool, 0), + ("int_neg", Signed, 2), + ("int_neg", Signed, -2), + ("int_invert", Signed, 5), + ("int_invert", Signed, -5), + + # binary ("int_add", Signed, 1, 2), ("int_sub", Signed, 1, 3), ("int_mul", Signed, 2, 3), ("int_div", Signed, 7, 3), ("int_floordiv", Signed, 7, 3), ("int_floordiv", Signed, -7, 3), - ("int_abs", Signed, 7), - ("int_abs", Signed, -7), ] for t in tests: yield optest, t From ludal at codespeak.net Mon Mar 13 19:31:30 2006 From: ludal at codespeak.net (ludal at codespeak.net) Date: Mon, 13 Mar 2006 19:31:30 +0100 (CET) Subject: [pypy-svn] r24318 - pypy/dist/pypy/lib/logic/gecode_wrapper Message-ID: <20060313183130.8691010095@code0.codespeak.net> Author: ludal Date: Mon Mar 13 19:31:28 2006 New Revision: 24318 Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.cc pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.hh pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrapper_gen.py (contents, props changed) Log: starting a wrapper generator Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.cc ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.cc Mon Mar 13 19:31:28 2006 @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include "kernel.hh" +#include "int.hh" +#include "search.hh" + +#include "gecode_wrap.hh" + + + +%(var_subclasses_body)s + +%(var_factories_body)s + +%(var_propagators_body)s Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.hh ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrap_tmpl.hh Mon Mar 13 19:31:28 2006 @@ -0,0 +1,46 @@ +#ifndef GECODE_WRAP_HH +#define GECODE_WRAP_HH + +#include +#include "kernel.hh" +#include "int.hh" +#include "search.hh" +#include "py_gecode_types.hh" + +class PySpace; + +class PyVar { +public: + PyVar() {} + virtual update(); +}; + +%(var_subclasses_decl)s + +class PySpace : public Gecode::Space { +public: + PySpace() {} + + PySpace( bool share, PySpace& s ):Space(share,s), + vars(s.vars.size()) + { + var_vector_iterator its, itd; + for( its=s.vars.begin(), itd=vars.begin();itd!=vars.end(); ++its,++itd ) { + itd->update( this, share, *its ); + } + } + + %(var_factories_decl)s + + %(var_propagators_decl)s + + + virtual Space* copy( bool share ) { + return new PySpace( share, *this ); + } +protected: + var_vector vars; +}; + + +#endif GECODE_WRAP_HH Added: pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrapper_gen.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/gecode_wrapper/gecode_wrapper_gen.py Mon Mar 13 19:31:28 2006 @@ -0,0 +1,128 @@ +# wrapper code generator for gecode library + + +GECODE_WRAP_HH = file("gecode_wrap_tmpl.hh").read() +GECODE_WRAP_CC = file("gecode_wrap_tmpl.cc").read() + +VAR_CLASS_DEF = """ +class Py%(var_type)s : public PyVar { +public: + /* constructor */ + Py%(var_type)s( PySpace* space, %(var_factory_args)s ); + virtual void update( PySpace* space, bool share, Py%(var_type)s& _var ); + + virtual %(value_type)s val() { return var.val(); } + + %(var_type)s var; +}; +""" + +VAR_CLASS_BODY = """ +Py%(var_type)s::Py%(var_type)s( PySpace* space, %(var_factory_args)s ):var(space, %(var_args)s ) +{ +} + +void +Py%(var_type)s::update( PySpace* space, bool share, Py%(var_type)s& _var ) +{ + var.update( space, share, _var ); +} + +""" + +VARACCESS = """ + %(var_type)s* get%(var_type)s( int i ) { return &(dynamic_cast(&vars[i])->var); } +""" + +VARTYPES = [ { 'var_type' : 'IntVar', + 'value_type' : 'int', + 'args' : [ ('int', 'min'), ('int', 'max') ], + 'propagators' : [], + }, + { 'var_type' : 'BoolVar', + 'value_type' : 'int', + 'args' : [('int', 'min'), ('int', 'max') ], + 'propagators' : [], + }, +## { 'var_type' : 'SetVar', +## }, + ] + +for vardef in VARTYPES: + vardef['var_factory_args'] = ", ".join( [ "%s _%s" % (typ,nam) for typ, nam in vardef['args'] ] ) + vardef['var_args'] = ", ".join( [ "_%s" % nam for typ, nam in vardef['args'] ] ) + vardef['var_storage'] = '_'+vardef['var_type'] + "_vect" + vardef['var_storage_temp'] = '_'+vardef['var_type'] + "_tmp_vect" + + +VAR_FACTORY_DEF = """ + int %(var_type)s( %(var_factory_args)s ); + int %(var_type)s_temp( %(var_factory_args)s ); +""" + +VAR_FACTORY_BODY = """ +int PySpace::%(var_type)s( %(var_factory_args)s ) { + %(var_storage)s.push_back( %(var_type)s( %(var_args)s ) ); + return %(var_storage)s.size(); + } + +int PySpace::%(var_type)s_temp( %(var_factory_args)s ) { + %(var_storage_temp)s.push_back( %(var_type)s( %(var_args)s ) ); + return %(var_storage)s.size(); + } +""" + +VAR_ACCESSOR = """ + void get%(var_type)sValues( int idx, int n, int* vars, %(var_type)s* values ) { + for(int i=0;ival(); + } + } + } +""" + +PROPCOND = [] + + + + +def create_var_subclasses( d ): + out_hh = [] + out_cc = [] + for vardef in VARTYPES: + out_hh.append( VAR_CLASS_DEF % vardef ) + out_cc.append( VAR_CLASS_BODY % vardef ) + d['var_subclasses_decl'] = "\n".join( out_hh ) + d['var_subclasses_body'] = "\n".join( out_cc ) + +def create_var_factories( d ): + out_hh = [] + out_cc = [] + for vardef in VARTYPES: + out_hh.append( VAR_FACTORY_DEF % vardef ) + out_cc.append( VAR_FACTORY_BODY % vardef ) + + d['var_factories_decl'] = "\n".join( out_hh ) + d['var_factories_body'] = "\n".join( out_cc ) + +def create_var_propagators( d ): + out_hh = [] + out_cc = [] + + d['var_propagators_decl'] = "\n".join( out_hh ) + d['var_propagators_body'] = "\n".join( out_cc ) + + +if __name__ == "__main__": + wrapper_hh = file("_gecode_wrap.hh", "w") + wrapper_cc = file("_gecode_wrap.cc", "w") + d = {} + + create_var_subclasses( d ) + create_var_factories( d ) + create_var_propagators( d ) + + wrapper_hh.write( GECODE_WRAP_HH % d ) + wrapper_cc.write( GECODE_WRAP_CC % d ) From tismer at codespeak.net Mon Mar 13 19:39:46 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 13 Mar 2006 19:39:46 +0100 (CET) Subject: [pypy-svn] r24319 - pypy/dist/pypy/translator/c/winproj/extension Message-ID: <20060313183946.46FF01009A@code0.codespeak.net> Author: tismer Date: Mon Mar 13 19:39:25 2006 New Revision: 24319 Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Log: corrections to debug buold Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Mon Mar 13 19:39:25 2006 @@ -34,7 +34,7 @@ + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-306\testing_1\common_header.h"> + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-306\testing_1\testing_1.c"> From auc at codespeak.net Mon Mar 13 22:50:24 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 13 Mar 2006 22:50:24 +0100 (CET) Subject: [pypy-svn] r24320 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060313215024.ED1C810095@code0.codespeak.net> Author: auc Date: Mon Mar 13 22:50:23 2006 New Revision: 24320 Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_variable.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: added waitneeded some refactoring, still one test to fix Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Mon Mar 13 22:50:23 2006 @@ -36,6 +36,12 @@ x = sp.var('x') raises(v.AlreadyInStore, sp.var, 'x') + def test_get_by_name(self): + sp = newspace() + x = sp.var('x') + assert x == sp.get_var_by_name('x') + raises(space.NotInStore, sp.get_var_by_name, 'y') + def test_already_bound(self): sp = newspace() x = sp.var('x') Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Mon Mar 13 22:50:23 2006 @@ -3,9 +3,7 @@ from py.test import raises -import computationspace as space -import variable as v -from problems import dummy_problem +from variable import var, NoValue, AlreadyBound #-- utilities --------------------- @@ -35,21 +33,17 @@ def run(self): val = [var.wait() for var in self.vars] -def newspace(): - return space.ComputationSpace(dummy_problem) - - #-- meat ---------------------------- class TestSimpleVariable: def test_basics(self): - x = v.SimpleVar() - assert x.val == v.NoValue + x = var() + assert x.val == NoValue x.bind(42) assert x.val == 42 x.bind(42) - raises(v.AlreadyBound, x.bind, 43) + raises(AlreadyBound, x.bind, 43) def test_dataflow(self): def fun(thread, var): @@ -57,7 +51,7 @@ v = var.wait() thread.state = v - x = v.SimpleVar() + x = var() t = FunThread(fun, x) import time t.start() @@ -74,67 +68,18 @@ thread.res += v[0] consummer(thread, v[1]) - S = v.SimpleVar() + S = var() t = FunThread(consummer, S) t.res = 0 t.start() for i in range(10): - tail = v.SimpleVar() + tail = var() S.bind((i, tail)) S = tail S.bind(None) t.join() assert t.res == 45 -class TestCsVariable: - - def test_no_same_name(self): - sp = newspace() - x = sp.var('x') - raises(space.AlreadyInStore, sp.var, 'x') - - def test_get_by_name(self): - sp = newspace() - x = sp.var('x') - assert x == sp.get_var_by_name('x') - raises(space.NotInStore, sp.get_var_by_name, 'y') - - def test_one_thread_reading_one_var(self): - sp = newspace() - cons = Consumer() - x = sp.var('x') - cons.give_var(x) - cons.start() - sp.bind(x, 42) - cons.join() - assert cons.var.val == 42 - - def test_many_threads_reading_one_var(self): - sp = newspace() - conss = [Consumer() for i in range(10)] - x = sp.var('x') - for cons in conss: - cons.give_var(x) - cons.start() - sp.bind(x, 42) - for cons in conss: - cons.join() - assert cons.var.val == 42 - - def test_many_thread_reading_many_var(self): - sp = newspace() - conss = [NConsumer() for i in range(10)] - vars_ = [sp.var(str(i)) for i in range(10)] - for cons in conss: - cons.give_vars(vars_) - cons.start() - for var in vars_: - sp.bind(var, var.name) - for cons in conss: - cons.join() - for i in range(10): - assert vars_[i].val == str(i) - #-- concurrent streams and lists ---------------- #-- utilities ----------------------------------- @@ -150,12 +95,11 @@ else nil end end""" if n 0: - sp = newspace() # fill Xs with an empty pair - X = sp.var('X') - Xr = sp.var('Xr') + X = var() + Xr = var() print "CLIENT binds Xs to X|Xr" Xs.bind((X, Xr)) x = X.wait() # wait on the value of X @@ -210,21 +152,26 @@ end end""" X_Xr = Xs.wait() - if X_Xr == EOL: + if X_Xr == None: thread.result = a return Xr = X_Xr[1] reduc(thread, Xr, fun(a, X_Xr[0]), fun) +def run_test(t1, t2): + t1.start() + t2.start() + t1.join() + t2.join() + + #-- meat ---------------------------------------- class TestStream: def test_multiple_readers_eager_list(self): """the generator controls the flow""" - sp = newspace() - - Xs = sp.var('L') + Xs = var() r1 = FunThread(reduc, Xs, 0, operator.add) r2 = FunThread(reduc, Xs, 0, operator.add) @@ -242,40 +189,67 @@ assert r.result == 861 def test_lazy_list(self): - """the reader controls the flow""" - sp = newspace() - - def run_test(t1, t2): - """ - local Xs S in - thread {DGenerate 0 Xs} end - thread S={DSum Xs 0 15} end - {Browse S} - end""" - t1.start() - t2.start() - t1.join() - t2.join() - - Xs = sp.var('Xs') + """the reader controls the flow + local Xs S in + thread {DGenerate 0 Xs} end + thread S={DSum Xs 0 15} end + {Browse S} + end""" + Xs = var() generator = FunThread(dgenerate, 0, Xs) summer = FunThread(dsum, Xs, 0, 15) run_test(generator, summer) assert summer.result == 105 + def test_wait_needed(self): + """lazyness by wait_needed""" + Xs = var() + + def lgenerate(thread, n, Xs): + """wait-needed version of dgenerate""" + print "GENERATOR waits on Xs" + Xs.wait_needed() + Xr = var() + Xs.bind((n, Xr)) + print "GENERATOR binds Xs to", n + dgenerate(thread, n+1, Xr) + + def sum(thread, Xs, a, limit): + """much shorter than dsum""" + if limit > 0: + x = Xs.wait() + print "CLIENT got", x + dsum(thread, x[1], a+x[0], limit-1) + else: + thread.result = a + + generator = FunThread(lgenerate, 0, Xs) + summer = FunThread(sum, Xs, 0, 15) + + run_test(generator, summer) + assert summer.result == 105 + def test_bounded_buffer_transducer(self): """reader controls the flow but a buffer between generator/consummer avoids inefficient step-wise progression """ - sp = newspace() + def print_stream(S): + while S.is_bound(): + v = S.wait() + if isinstance(v, tuple): + v0 = v[0] + if v0.is_bound(): print v0, '|', + else: print '?' ; break + S = v[1] + else: + print v + break def bounded_buffer(thread, n, Xs, Ys): - sp = newspace() - def startup(n, Xs): """ fun {Startup N ?Xs} @@ -284,10 +258,10 @@ end """ if n==0: return Xs - sp = newspace() - X_ = sp.var('X_') - Xr = sp.var('Xr') - Xs.bind((X_, Xr)) + print "startup n = ", n, + print_stream(Xs) + Xr = var() + Xs.bind((var(), Xr)) return startup(n-1, Xr) def ask_loop(Ys, Xs, End): @@ -300,29 +274,32 @@ end end """ - sp = newspace() + print "Ask_loop ..." + print_stream(Xs) + print_stream(Ys) Y_Yr = Ys.wait() # destructure Ys if Y_Yr != None: Y, Yr = Y_Yr + print "Ask_loop in thread %s got %s %s " % \ + (thread.getName(), Y, Yr) X, Xr = Xs.wait() Y.bind(X.wait()) - End2 = sp.var('End2') - X_ = sp.var('X_') - End.bind((X_, End2)) + End2 = var() + End.bind((var(), End2)) ask_loop(Yr, Xr, End2) else: End.bind(None) - End = sp.var('End') + End = var() End.bind(startup(n, Xs)) print "BUFFER starts" ask_loop(Ys, Xs, End) - Xs = sp.var('Xs') - Ys = sp.var('Ys') + Xs = var() + Ys = var() generator = FunThread(dgenerate, 0, Xs) - bbuffer = FunThread(bounded_buffer, 8, Xs, Ys) + bbuffer = FunThread(bounded_buffer, 4, Xs, Ys) summer = FunThread(dsum, Ys, 0, 50) generator.start() Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Mon Mar 13 22:50:23 2006 @@ -31,6 +31,9 @@ class NoDom: pass +def var(): + return SimpleVar() + class SimpleVar(object): """Spaceless dataflow variable""" @@ -39,6 +42,7 @@ self._val = NoValue # a condition variable for concurrent access self._value_condition = threading.Condition() + self._need_condition = threading.Condition() # value accessors def _set_val(self, val): @@ -56,6 +60,13 @@ return self._val val = property(_get_val, _set_val) + def __str__(self): + if self.is_bound(): + return "%s = %s" % (self.name, self.val) + return "%s" % self.name + + def __repr__(self): + return self.__str__() # public interface @@ -67,22 +78,34 @@ def wait(self): try: + self._need_condition.acquire() + self._need_condition.notifyAll() + finally: + self._need_condition.release() + try: self._value_condition.acquire() while not self.is_bound(): t1 = time.time() - self._value_condition.wait(120) + self._value_condition.wait(10) t2 = time.time() - if t2-t1>120: + if t2-t1>10: raise RuntimeError("possible deadlock??") return self.val finally: self._value_condition.release() - + + def wait_needed(self): + try: + self._need_condition.acquire() + self._need_condition.wait() + finally: + self._need_condition.release() class CsVar(SimpleVar): """Dataflow variable linked to a space""" def __init__(self, name, cs): + SimpleVar.__init__(self) if name in cs.names: raise AlreadyInStore(name) self.name = name @@ -129,14 +152,6 @@ return self._val val = property(_get_val, _set_val) - def __str__(self): - if self.is_bound(): - return "%s = %s" % (self.name, self.val) - return "%s" % self.name - - def __repr__(self): - return self.__str__() - def bind(self, val): """home space bind""" self._cs.bind(self, val) From nik at codespeak.net Mon Mar 13 23:16:32 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 13 Mar 2006 23:16:32 +0100 (CET) Subject: [pypy-svn] r24321 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060313221632.05AED10097@code0.codespeak.net> Author: nik Date: Mon Mar 13 23:16:26 2006 New Revision: 24321 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_llops.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: - an attempt at a general solution to integer llops and wraparound for the various rpython datatypes. still a bit clumsy. - deleted old tests that didn't really prove anything and are hard to keep green with gensqueak heavily in flux. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Mon Mar 13 23:16:26 2006 @@ -244,19 +244,34 @@ 'runtimenew': Selector('new', 0), 'classof': Selector('class', 0), 'sameAs': Selector('yourself', 0), - - # XXX need to handle overflow for all integer ops - 'intAbs': Selector('abs', 0), - 'intIsTrue': Selector('isZero not', 0), - 'intNeg': Selector('negated', 0), - 'intInvert': Selector('bitInvert', 0), # maybe bitInvert32? - - 'intAdd:': Selector('+', 1), - 'intSub:': Selector('-', 1), - 'intEq:': Selector('=', 1), - 'intMul:': Selector('*', 1), - 'intDiv:': Selector('//', 1), - 'intFloordiv:': Selector('//', 1), + } + + primitive_ops = { + 'abs': 'abs', + 'is_true': 'isZero not', + 'neg': 'negated', + 'invert': 'bitInvert', # maybe bitInvert32? + + 'add': '+', + 'sub': '-', + 'eq': '=', + 'mul': '*', + 'div': '//', + 'floordiv': '//', + } + + primitive_opprefixes = "int", "uint", "llong", "ullong", "float" + + primitive_wrapping_ops = "add", "sub", "mul" + + primitive_masks = { + # XXX horrendous, but I can't figure out how to do this cleanly + "int": (Selector("maskInt", 1), + """maskInt: i + ((i <= %s) & (i >= %s)) ifTrue: [^i]. + ^ i + %s \\\\ %s - %s + """ % (sys.maxint, -sys.maxint-1, + sys.maxint+1, 2*(sys.maxint+1), sys.maxint+1)), } def render_body(self, startblock): @@ -284,6 +299,10 @@ raise TypeError, "expr(%r)" % (v,) def oper(self, op): + opname_parts = op.opname.split("_") + if opname_parts[0] in self.primitive_opprefixes: + return self.oper_primitive( + op, opname_parts[0], "_".join(opname_parts[1:])) op_method = getattr(self, "op_%s" % op.opname, None) if op_method is not None: return op_method(op) @@ -293,6 +312,19 @@ args = [self.expr(arg) for arg in op.args[1:]] return self.assignment(op, receiver, name, args) + def oper_primitive(self, op, ptype, opname): + receiver = self.expr(op.args[0]) + args = [self.expr(arg) for arg in op.args[1:]] + sel = Selector(self.primitive_ops[opname], len(args)) + message = "%s %s" % (receiver, sel.signature(args)) + if opname in self.primitive_wrapping_ops \ + and self.primitive_masks.has_key(ptype): + mask_selector, mask_code = self.primitive_masks[ptype] + helper = HelperNode(self.gen, mask_selector, mask_code) + message = helper.apply(["(%s)" % message]) + self.gen.schedule_node(helper) + return "%s := %s." % (self.expr(op.result), message) + def assignment(self, op, receiver_name, sel_name, arg_names): sel = Selector(sel_name, len(arg_names)) if op.opname != "oosend": @@ -482,6 +514,29 @@ yield " ^%s" % self.field_name yield "! !" +class HelperNode(CodeNode): + + HELPERS = Instance("Helpers", ROOT) + + def __init__(self, gen, selector, code): + self.gen = gen + self.selector = selector + self.code = code + self.hash_key = ("helper", code) + + def apply(self, args): + return "PyHelpers %s" % self.selector.signature(args) + + def dependencies(self): + return [ClassNode(self.gen, self.HELPERS)] + + def render(self): + # XXX should not use explicit name "PyHelpers" here + yield self.render_fileout_header("PyHelpers class", "helpers") + for line in self.code.strip().split("\n"): + yield line + yield "! !" + class FieldInitializerNode(CodeNode): def __init__(self, gen, INSTANCE): Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 13 23:16:26 2006 @@ -1,3 +1,4 @@ +import sys from pypy.translator.squeak.test.runtest import compile_function from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop @@ -20,12 +21,10 @@ sqfunc = compile_function(lloptest, annotation) expected_res = interpret(lloptest, args, policy=LowLevelAnnotatorPolicy()) res = sqfunc(*args) - assert res == str(res).lower() # lowercasing for booleans + assert res == str(expected_res).lower() # lowercasing for booleans def test_intoperations(): tests = [ - # XXX Must handle overflows for all integer ops - # unary ("int_abs", Signed, 7), ("int_abs", Signed, -7), @@ -43,6 +42,11 @@ ("int_div", Signed, 7, 3), ("int_floordiv", Signed, 7, 3), ("int_floordiv", Signed, -7, 3), + + # binary wraparounds + ("int_add", Signed, sys.maxint, 1), + ("int_sub", Signed, -sys.maxint-1, 2), + ("int_mul", Signed, sys.maxint/2, 3), ] for t in tests: yield optest, t Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Mon Mar 13 23:16:26 2006 @@ -4,28 +4,6 @@ from pypy.translator.squeak.gensqueak import Selector, camel_case from pypy.translator.squeak.test.runtest import compile_function - -def looping(i, j): - while i > 0: - i -= 1 - while j > 0: - j -= 1 - -class TestSqueakTrans: - - def test_simple_func(self): - compile_function(snippet.simple_func, [int]) - - def test_if_then_else(self): - compile_function(snippet.if_then_else, [bool, int, int]) - - def test_my_gcd(self): - compile_function(snippet.my_gcd, [int, int]) - - def test_looping(self): - compile_function(looping, [int, int]) - - class TestGenSqueak: def test_theanswer(self): From tismer at codespeak.net Tue Mar 14 03:32:42 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 14 Mar 2006 03:32:42 +0100 (CET) Subject: [pypy-svn] r24324 - pypy/dist/pypy/rpython Message-ID: <20060314023242.980E510098@code0.codespeak.net> Author: tismer Date: Tue Mar 14 03:32:17 2006 New Revision: 24324 Modified: pypy/dist/pypy/rpython/extregistry.py Log: bad indent Modified: pypy/dist/pypy/rpython/extregistry.py ============================================================================== --- pypy/dist/pypy/rpython/extregistry.py (original) +++ pypy/dist/pypy/rpython/extregistry.py Tue Mar 14 03:32:17 2006 @@ -33,7 +33,7 @@ return annotation def create_entry(compute_result_annotation=None, compute_annotation=None, - specialize_call=None, get_repr=None): + specialize_call=None, get_repr=None): if compute_result_annotation is not None: compute_result_annotation = create_annotation_callable( compute_result_annotation) From tismer at codespeak.net Tue Mar 14 03:44:00 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 14 Mar 2006 03:44:00 +0100 (CET) Subject: [pypy-svn] r24325 - pypy/dist/pypy/translator/test Message-ID: <20060314024400.C59DC10098@code0.codespeak.net> Author: tismer Date: Tue Mar 14 03:43:49 2006 New Revision: 24325 Modified: pypy/dist/pypy/translator/test/test_extension.py Log: another simple test Modified: pypy/dist/pypy/translator/test/test_extension.py ============================================================================== --- pypy/dist/pypy/translator/test/test_extension.py (original) +++ pypy/dist/pypy/translator/test/test_extension.py Tue Mar 14 03:43:49 2006 @@ -65,5 +65,5 @@ bigval = 123456789012345l assert raises(OverflowError, f, bigval) assert g(bigval) == example_obj_long(bigval) - - \ No newline at end of file + assert g(float(bigval)) == example_obj_long(bigval) + assert raises(TypeError, g, str(bigval)) From tismer at codespeak.net Tue Mar 14 03:48:03 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 14 Mar 2006 03:48:03 +0100 (CET) Subject: [pypy-svn] r24326 - in pypy/dist/pypy: annotation translator/test Message-ID: <20060314024803.1267610098@code0.codespeak.net> Author: tismer Date: Tue Mar 14 03:47:52 2006 New Revision: 24326 Modified: pypy/dist/pypy/annotation/registry.py pypy/dist/pypy/translator/test/test_extension.py Log: shuffled doc strings where they belong. Hey, I seem to be a rare animal in this project, writing doc strings Modified: pypy/dist/pypy/annotation/registry.py ============================================================================== --- pypy/dist/pypy/annotation/registry.py (original) +++ pypy/dist/pypy/annotation/registry.py Tue Mar 14 03:47:52 2006 @@ -3,8 +3,14 @@ Reason: building extension modules. -This is a first attempt to have a way to declare what -we cannot translate, but want to get handled in some way. +A simple approach to support building extension modules. +The key idea is to provide a mechanism to record certain objects +and types to be recognized as SomeObject, to be created using imports +without trying to further investigate them. + +This is intentionally using global dicts, since what we can +translate is growing in time, but usually nothing you want +to configure dynamically. """ import sys Modified: pypy/dist/pypy/translator/test/test_extension.py ============================================================================== --- pypy/dist/pypy/translator/test/test_extension.py (original) +++ pypy/dist/pypy/translator/test/test_extension.py Tue Mar 14 03:47:52 2006 @@ -3,16 +3,7 @@ from pypy import conftest from py.test import raises -""" -This is a simple approach to support building extension moduels. -The key idea is to provide a mechanism to record certain objects -and types to be recognized as SomeObject, to be created using imports -without trying to further investigate them. - -This is intentionally using global dicts, since what we can -translate is growing in time, but usually nothing you want -to configure dynamically. -""" +# see annotation/registry for comments def get_annotation(func): argstypelist = [] From goden at codespeak.net Tue Mar 14 06:31:57 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Tue, 14 Mar 2006 06:31:57 +0100 (CET) Subject: [pypy-svn] r24328 - pypy/dist/pypy/doc Message-ID: <20060314053157.7F36B10098@code0.codespeak.net> Author: goden Date: Tue Mar 14 06:31:52 2006 New Revision: 24328 Modified: pypy/dist/pypy/doc/ctypes-integration.txt Log: - trivial corrections Modified: pypy/dist/pypy/doc/ctypes-integration.txt ============================================================================== --- pypy/dist/pypy/doc/ctypes-integration.txt (original) +++ pypy/dist/pypy/doc/ctypes-integration.txt Tue Mar 14 06:31:52 2006 @@ -72,10 +72,10 @@ Thus the annotator tracks the memory state of each ctypes object. Pointers to structures are annotated differently when they are return by an external -function. As stated abbove a mixed memory mode function result type is not -considered rctypes compliant and therefore annotated as `SomeObject` [#]. +function. As stated above a mixed memory mode function result type is not +considered rctypes compliant and therefore annotated as `SomeObject` [#]_. -..[#] This restriction will be lifted in future ctypes versions. +.. [#] This restriction will be lifted in future ctypes versions. Memory-Layout ------------- From goden at codespeak.net Tue Mar 14 06:37:37 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Tue, 14 Mar 2006 06:37:37 +0100 (CET) Subject: [pypy-svn] r24329 - pypy/dist/pypy/rpython/rctypes/test Message-ID: <20060314053737.8A8ED10098@code0.codespeak.net> Author: goden Date: Tue Mar 14 06:37:34 2006 New Revision: 24329 Modified: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Log: added try/except around ctypes import for test_rprimitive.py. added test cases for c_float() for the fun of it. came across some strange rounding behavior for statically allocated c_float(). nothing which couldn't be fixed with a ("%.2f" % res) == ("%.2f" % 4.2). :) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py Tue Mar 14 06:37:34 2006 @@ -11,6 +11,11 @@ import sys from pypy.rpython.test.test_llinterp import interpret +try: + import ctypes +except ImportError: + py.test.skip("this test needs ctypes installed") + from ctypes import c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint from ctypes import c_long, c_ulong, c_longlong, c_ulonglong, c_float from ctypes import c_double, c_char_p @@ -65,6 +70,52 @@ if conftest.option.view: t.view() + + def test_annotate_c_float(self): + def func(): + res = c_float(4.2) + + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == float + + if conftest.option.view: + t.view() + + def test_annotate_prebuilt_c_float(self): + res = c_float(4.2) + + def func(): + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == float + + if conftest.option.view: + t.view() + + def test_annotate_set_c_float_value(self): + def func(): + res = c_float(4.2) + res.value = 5.2 + + return res.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + assert s.knowntype == float + + if conftest.option.view: + t.view() class Test_specialization: def test_specialize_c_int(self): @@ -80,7 +131,7 @@ res = interpret(create_c_int, []) c_data = res.c_data assert c_data.value == 0 - + def test_specialize_c_int_access_value(self): def create_c_int(): return c_int(42).value @@ -104,6 +155,49 @@ res = interpret(access_cint, []) assert res == 42 + def test_specialize_c_float(self): + def create_c_float(): + return c_float(4.2) + res = interpret(create_c_float, []) + c_data = res.c_data + assert c_data.value == 4.2 + + def test_specialize_c_float_default_value(self): + def create_c_float(): + return c_float() + res = interpret(create_c_float, []) + c_data = res.c_data + assert c_data.value == 0.0 + + def test_specialize_c_float_access_value(self): + def create_c_float(): + return c_float(4.2).value + res = interpret(create_c_float, []) + assert res == 4.2 + + def test_specialize_c_float_set_value(self): + def set_c_float_value(): + cf = c_float(4.2) + cf.value = 5.2 + return cf.value + + res = interpret(set_c_float_value, []) + assert res == 5.2 + + def test_specialize_access_prebuilt_c_float_value(self): + cf = c_float(4.3) + def access_c_float(): + return cf.value + + res = interpret(access_c_float, []) + + # XXX: goden: Not sure if this is an indication of some sort of + # problem, but the precision appears to be broken when + # returning a float from the interpreted function when its + # statically allocated. As a temporary hack I'm reducing + # the precision to compare. + assert ("%.2f" % res) == ("%.2f" % 4.3) + class Test_compilation: def test_compile_c_int(self): def create_c_int(): @@ -127,3 +221,31 @@ fn = compile(access_cint, []) assert fn() == 52 + + def test_compile_c_float(self): + def create_c_float(): + return c_float(4.2).value + fn = compile(create_c_float, []) + assert fn() == 4.2 + + def test_compile_prebuilt_c_float(self): + cf = c_float(4.2) + def access_c_float(): + return cf.value + + fn = compile(access_c_float, []) + # XXX: goden: Not sure if this is an indication of some sort of + # problem, but the precision appears to be broken when + # returning a float from the interpreted function when its + # statically allocated. As a temporary hack I'm reducing + # the precision to compare. + assert ("%.2f" % (fn(),)) == ("%.2f" % (4.2,)) + + def test_compile_set_prebuilt_c_float_value(self): + cf = c_float(4.2) + def access_c_float(): + cf.value = 5.2 + return cf.value + + fn = compile(access_c_float, []) + assert fn() == 5.2 From nik at codespeak.net Tue Mar 14 11:56:22 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 14 Mar 2006 11:56:22 +0100 (CET) Subject: [pypy-svn] r24356 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060314105622.B6F0910094@code0.codespeak.net> Author: nik Date: Tue Mar 14 11:56:11 2006 New Revision: 24356 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: more awkward code to support uint llops. some major refactoring will be required soon, mainly splitting up code into more modules. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Tue Mar 14 11:56:11 2006 @@ -7,6 +7,7 @@ from pypy.translator.unsimplify import remove_direct_loops from pypy.translator.simplify import simplify_graph from pypy.rpython.ootypesystem.ootype import Instance, ROOT +from pypy.rpython.rarithmetic import r_int, r_uint from pypy import conftest try: set @@ -262,7 +263,7 @@ primitive_opprefixes = "int", "uint", "llong", "ullong", "float" - primitive_wrapping_ops = "add", "sub", "mul" + primitive_wrapping_ops = "neg", "invert", "add", "sub", "mul" primitive_masks = { # XXX horrendous, but I can't figure out how to do this cleanly @@ -272,6 +273,9 @@ ^ i + %s \\\\ %s - %s """ % (sys.maxint, -sys.maxint-1, sys.maxint+1, 2*(sys.maxint+1), sys.maxint+1)), + "uint": (Selector("maskUint", 1), + """maskUint: i + ^ i bitAnd: %s""" % r_uint.MASK), } def render_body(self, startblock): Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Tue Mar 14 11:56:11 2006 @@ -1,8 +1,9 @@ import sys from pypy.translator.squeak.test.runtest import compile_function +from pypy.rpython.rarithmetic import r_uint from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.lltypesystem.lltype import Signed, Bool +from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Bool from pypy.rpython.test.test_llinterp import interpret def optest(testcase): @@ -23,26 +24,39 @@ res = sqfunc(*args) assert res == str(expected_res).lower() # lowercasing for booleans -def test_intoperations(): - tests = [ - # unary - ("int_abs", Signed, 7), - ("int_abs", Signed, -7), - ("int_is_true", Bool, 8), - ("int_is_true", Bool, 0), - ("int_neg", Signed, 2), - ("int_neg", Signed, -2), - ("int_invert", Signed, 5), - ("int_invert", Signed, -5), - - # binary - ("int_add", Signed, 1, 2), - ("int_sub", Signed, 1, 3), - ("int_mul", Signed, 2, 3), - ("int_div", Signed, 7, 3), - ("int_floordiv", Signed, 7, 3), - ("int_floordiv", Signed, -7, 3), +def adapt_tests(tests, type, RESTYPE, prefix): + adapted = [] + for test in tests: + llop = "%s_%s" % (prefix, test[0]) + RES = test[1] + if RES == Signed: + RES = RESTYPE + args = [type(arg) for arg in test[2:]] + adapted.append((llop, RES) + tuple(args)) + return adapted + +general_tests = [ + # unary + ("abs", Signed, 7), + ("abs", Signed, -7), + ("is_true", Bool, 8), + ("is_true", Bool, 0), + ("neg", Signed, 2), + ("neg", Signed, -2), + ("invert", Signed, 5), + ("invert", Signed, -5), + + # binary + ("add", Signed, 1, 2), + ("sub", Signed, 1, 3), + ("mul", Signed, 2, 3), + ("div", Signed, 7, 3), + ("floordiv", Signed, 7, 3), + ("floordiv", Signed, -7, 3), +] +def test_intoperations(): + tests = adapt_tests(general_tests, int, Signed, "int") + [ # binary wraparounds ("int_add", Signed, sys.maxint, 1), ("int_sub", Signed, -sys.maxint-1, 2), @@ -51,3 +65,12 @@ for t in tests: yield optest, t +def test_uintoperations(): + tests = adapt_tests(general_tests, r_uint, Unsigned, "uint") + [ + # binary wraparounds + ("uint_add", Unsigned, r_uint(2*sys.maxint), r_uint(2)), + ("uint_mul", Unsigned, r_uint(sys.maxint), r_uint(3)), + ] + for t in tests: + yield optest, t + From mwh at codespeak.net Tue Mar 14 12:56:10 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Mar 2006 12:56:10 +0100 (CET) Subject: [pypy-svn] r24357 - in pypy/dist/pypy: rpython rpython/memory translator/c Message-ID: <20060314115610.24BBB10094@code0.codespeak.net> Author: mwh Date: Tue Mar 14 12:56:08 2006 New Revision: 24357 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/rpython/rstr.py pypy/dist/pypy/translator/c/node.py Log: use a much much more explicit way to specialcase adding a byte to all strings for the NULL. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Tue Mar 14 12:56:08 2006 @@ -9,7 +9,6 @@ from pypy.rpython import rmodel, rptr, annlowlevel from pypy.rpython.memory import gc, lladdress from pypy.rpython.annlowlevel import MixLevelHelperAnnotator -from pypy.rpython.rstr import STR import sets, os EXCEPTION_RAISING_OPS = ['direct_call', 'indirect_call'] @@ -828,7 +827,7 @@ info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0) else: info["fixedsize"] = ofs1 + llmemory.sizeof(lltype.Signed) - if TYPE is STR: + if ARRAY._hints.get('isrpystring'): info["fixedsize"] = llmemory.sizeof(TYPE, 1) else: ARRAY = TYPE Modified: pypy/dist/pypy/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/dist/pypy/rpython/rstr.py Tue Mar 14 12:56:08 2006 @@ -26,7 +26,8 @@ # } STR = GcStruct('rpy_string', ('hash', Signed), - ('chars', Array(Char, hints={'immutable': True}))) + ('chars', Array(Char, hints={'immutable': True, + 'isrpystring': True}))) SIGNED_ARRAY = GcArray(Signed) Modified: pypy/dist/pypy/translator/c/node.py ============================================================================== --- pypy/dist/pypy/translator/c/node.py (original) +++ pypy/dist/pypy/translator/c/node.py Tue Mar 14 12:56:08 2006 @@ -10,7 +10,6 @@ from pypy.translator.c.support import cdecl, somelettersfrom, c_string_constant from pypy.translator.c.primitive import PrimitiveType, isinf from pypy.translator.c import extfunc -from pypy.rpython.rstr import STR def needs_gcheader(T): @@ -142,7 +141,7 @@ original_varlength = varlength self.gcfields = [] - if ARRAY is STR.chars: + if ARRAY._hints.get('isrpystring'): varlength += 1 # for the NUL char terminator at the end of the string self.varlength = varlength if original_varlength == 1: From mwh at codespeak.net Tue Mar 14 13:05:09 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Mar 2006 13:05:09 +0100 (CET) Subject: [pypy-svn] r24358 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060314120509.B681A10094@code0.codespeak.net> Author: mwh Date: Tue Mar 14 13:05:08 2006 New Revision: 24358 Added: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (contents, props changed) Log: a skeleton of a sprint report. Added: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Tue Mar 14 13:05:08 2006 @@ -0,0 +1,35 @@ +Post-PyCon 2006 Sprint Report +============================= + +After PyCon this year, we held four days of sprints. There were lots +of people new to PyPy and a couple of old friends we hadn't seen for a +while. + +Day 1 +----- + +Monday began with a 45 minute introduction/tutorial by Michael (which +was videoed -- watch for it arriving on codespeak soon-ish) and then a +planning session, where we divided up into pairs or threes and decided +what we'd be working on for the rest of the day. + +This plan went out the window fairly quickly though, for a variety of +reasons... + +Day 2 +----- + +The Tuesday began with a status meeting where we talked about what +we'd acheived the day before and basically decided that most of us +would carry on with the same things (this proved to be a much more +accurate plan than the previous day's...). + +Day 3 +----- + +By Wednesday, the sprint was thinning out... + +Day 4 +----- + +XXX Did enough work get done on Thursday to even bother mentioning it? From cfbolz at codespeak.net Tue Mar 14 14:07:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 14 Mar 2006 14:07:10 +0100 (CET) Subject: [pypy-svn] r24359 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20060314130710.5A6DF10093@code0.codespeak.net> Author: cfbolz Date: Tue Mar 14 14:07:03 2006 New Revision: 24359 Modified: pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/backendopt/test/test_inline.py Log: don't inline direct_calls that have a cleanup attached. test. a disabled test that tests whether the inlines contained in the to be inlined function are copied Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Tue Mar 14 14:07:03 2006 @@ -60,6 +60,9 @@ subgraph, block, index_operation = callsites.pop() if find_callsites(subgraph, subgraph): raise CannotInline("inlining a recursive function") + operation = block.operations[index_operation] + if getattr(operation, "cleanup", None) is not None: + raise CannotInline("cannot inline a function with cleanup attached") _inline_function(translator, graph, block, index_operation) checkgraph(graph) count += 1 Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_inline.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_inline.py Tue Mar 14 14:07:03 2006 @@ -11,6 +11,7 @@ from pypy.rpython.llinterp import LLInterpreter from pypy.rpython.rarithmetic import ovfcheck from pypy.translator.test.snippet import is_perfect_number +from pypy.conftest import option def no_missing_concretetype(node): if isinstance(node, Block): @@ -380,4 +381,44 @@ return 1 assert x4() == 1 py.test.raises(CannotInline, check_inline, x3, x4, []) - + +def test_dont_inline_with_cleanups(): + from pypy.objspace.flow.model import Variable, SpaceOperation, Constant + from pypy.rpython.lltypesystem.lltype import Signed + import math + def f(x): + return math.sqrt(x) + def g(x): + return f(x) + t = translate(g, [int]) + graph = graphof(t, f) + ggraph = graphof(t, g) + xvar = ggraph.startblock.inputargs[0] + result = Variable() + result.concretetype = Signed + cleanupop = SpaceOperation("int_add", [Constant(1, Signed), xvar], result) + cleanup = ((cleanupop, ), (cleanupop, )) + ggraph.startblock.operations[0].cleanup = cleanup + py.test.raises(CannotInline, inline_function, t, f, ggraph) + +def DONOTtest_inline_copies_cleanups(): + from pypy.objspace.flow.model import Variable, SpaceOperation, Constant + from pypy.rpython.lltypesystem.lltype import Signed + import math + def f(x): + return math.sqrt(x) + def g(x): + return f(x) + t = translate(g, [int]) + graph = graphof(t, f) + ggraph = graphof(t, g) + xvar = graph.startblock.inputargs[0] + result = Variable() + result.concretetype = Signed + cleanupop = SpaceOperation("int_add", [Constant(1, Signed), xvar], result) + cleanup = ((cleanupop, ), (cleanupop, )) + graph.startblock.operations[0].cleanup = cleanup + inline_function(t, f, ggraph) + assert ggraph.startblock.operations[0].cleanup == cleanup + if option.view: + t.view() From ac at codespeak.net Tue Mar 14 14:52:08 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 14 Mar 2006 14:52:08 +0100 (CET) Subject: [pypy-svn] r24360 - pypy/dist/pypy/translator/microbench Message-ID: <20060314135208.67E871009A@code0.codespeak.net> Author: ac Date: Tue Mar 14 14:52:07 2006 New Revision: 24360 Modified: pypy/dist/pypy/translator/microbench/test_count1.py Log: (pedronis,arre) Some more benchmarks. Modified: pypy/dist/pypy/translator/microbench/test_count1.py ============================================================================== --- pypy/dist/pypy/translator/microbench/test_count1.py (original) +++ pypy/dist/pypy/translator/microbench/test_count1.py Tue Mar 14 14:52:07 2006 @@ -169,3 +169,35 @@ c = c + 1 # + +def test_count_in_attr(): + class X(object): + pass + x = X() + c = 0 + x.x = 0 + n = N + while c < n: + x.x = x.x + 1 + c += 1 + +x = 0 +def test_count_in_global(): + global x + c = 0 + x = 0 + n = N + while c < n: + x = x + 1 + c += 1 + + +def test_count_in_global2(): + global y + c = 0 + y = 0 + n = N + while c < n: + y = y + 1 + c += 1 + From auc at codespeak.net Tue Mar 14 16:35:35 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 14 Mar 2006 16:35:35 +0100 (CET) Subject: [pypy-svn] r24361 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060314153535.C9B0210092@code0.codespeak.net> Author: auc Date: Tue Mar 14 16:35:25 2006 New Revision: 24361 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_variable.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: more simplification Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Tue Mar 14 16:35:25 2006 @@ -9,8 +9,7 @@ from state import Succeeded, Failed, Unknown from variable import EqSet, CsVar, NoValue, NoDom, \ - VariableException, NotAVariable, AlreadyInStore, \ - AlreadyBound + VariableException, NotAVariable, AlreadyBound from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Tue Mar 14 16:35:25 2006 @@ -30,12 +30,6 @@ class TestStoreUnification: - - def test_already_in_store(self): - sp = newspace() - x = sp.var('x') - raises(v.AlreadyInStore, sp.var, 'x') - def test_get_by_name(self): sp = newspace() x = sp.var('x') Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Tue Mar 14 16:35:25 2006 @@ -3,7 +3,7 @@ from py.test import raises -from variable import var, NoValue, AlreadyBound +from variable import var, NoValue, AlreadyBound, stream_repr #-- utilities --------------------- @@ -45,40 +45,22 @@ x.bind(42) raises(AlreadyBound, x.bind, 43) - def test_dataflow(self): - def fun(thread, var): - thread.state = 1 - v = var.wait() - thread.state = v - + def test_repr_stream(self): + var._vcount = 0 #ensure consistent numbering x = var() - t = FunThread(fun, x) - import time - t.start() - time.sleep(.5) - assert t.state == 1 - x.bind(42) - t.join() - assert t.state == 42 - - def test_stream(self): - def consummer(thread, S): - v = S.wait() - if v: - thread.res += v[0] - consummer(thread, v[1]) - - S = var() - t = FunThread(consummer, S) - t.res = 0 - t.start() - for i in range(10): - tail = var() - S.bind((i, tail)) - S = tail - S.bind(None) - t.join() - assert t.res == 45 + it = x + for i in range(3): + it.bind((var(), var())) + it = it.wait()[1] + assert stream_repr(x) == '|||' + it.bind(None) + assert stream_repr(x) == '|||None' + it = x + for i in range(3): + it.wait()[0].bind(i) + it = it.wait()[1] + assert stream_repr(x) == '0|1|2|None' + #-- concurrent streams and lists ---------------- @@ -110,11 +92,12 @@ {DGenerate N+1 Xr} end end""" - print "GENERATOR in %s waits on Xs" % thread.getName() + print "generator in %s waits on Xs" % thread.getName() X_Xr = Xs.wait() # destructure Xs if X_Xr == None: return + print "generator X_Xr", X_Xr X = X_Xr[0] # ... into X - print "GENERATOR in %s binds X to %s" % (thread.getName(), n) + print "generator in %s binds X to %s" % (thread.getName(), n) X.bind(n) # bind X to n Xr = X_Xr[1] # ... and Xr dgenerate(thread, n+1, Xr) @@ -132,10 +115,10 @@ # fill Xs with an empty pair X = var() Xr = var() - print "CLIENT binds Xs to X|Xr" Xs.bind((X, Xr)) + print "client binds Xs to X|Xr ", stream_repr(Xs) x = X.wait() # wait on the value of X - print "CLIENT got", x + print "client got", x dsum(thread, Xr, a+x, limit-1) else: print "CLIENT binds Xs to None and exits" @@ -178,12 +161,12 @@ r3 = FunThread(reduc, Xs, 0, operator.add) generator = FunThread(generate, Xs, 0, 42) - r1.start() - r2.start() - r3.start() - generator.start() + for r in (r1, r2, r3): + r.start() + generator.start() generator.join() + for r in (r1, r2, r3): r.join() assert r.result == 861 @@ -236,18 +219,6 @@ buffer between generator/consummer avoids inefficient step-wise progression """ - def print_stream(S): - while S.is_bound(): - v = S.wait() - if isinstance(v, tuple): - v0 = v[0] - if v0.is_bound(): print v0, '|', - else: print '?' ; break - S = v[1] - else: - print v - break - def bounded_buffer(thread, n, Xs, Ys): def startup(n, Xs): @@ -257,11 +228,10 @@ else Xr in Xs=_|Xr {Startup N-1 Xr} end end """ - if n==0: return Xs - print "startup n = ", n, - print_stream(Xs) + if n==0: return Xs # will be End Xr = var() Xs.bind((var(), Xr)) + print "startup n = ", n, stream_repr(Xs) return startup(n-1, Xr) def ask_loop(Ys, Xs, End): @@ -274,14 +244,9 @@ end end """ - print "Ask_loop ..." - print_stream(Xs) - print_stream(Ys) Y_Yr = Ys.wait() # destructure Ys if Y_Yr != None: Y, Yr = Y_Yr - print "Ask_loop in thread %s got %s %s " % \ - (thread.getName(), Y, Yr) X, Xr = Xs.wait() Y.bind(X.wait()) End2 = var() @@ -290,10 +255,11 @@ else: End.bind(None) + print "buffer initial Ys, Xs ", stream_repr(Ys, Xs) End = var() End.bind(startup(n, Xs)) - print "BUFFER starts" - ask_loop(Ys, Xs, End) + print "buffer starts", stream_repr(Xs, End) + ask_loop(Ys, Xs, End.val) Xs = var() Ys = var() Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Tue Mar 14 16:35:25 2006 @@ -6,19 +6,15 @@ def __init__(self, name): self.name = name -class AlreadyInStore(VariableException): - def __str__(self): - return "%s already in store" % self.name - class AlreadyBound(Exception): def __init__(self, var, val): + print "can't bind %s to %s" % (var, val) self.var = var self.val = val def __str__(self): - return "%s:%s already bound to %s" % (self.var.name, - self.var.val, - self.val) + var, val = self.var, self.val + return "can't bind %s to %s" % (var, val) class NotAVariable(VariableException): def __str__(self): @@ -31,30 +27,30 @@ class NoDom: pass -def var(): - return SimpleVar() - -class SimpleVar(object): +class Var(object): """Spaceless dataflow variable""" + _count_lock = threading.Lock() + _vcount = 0 - def __init__(self): - self.name = str(id(self)) - self._val = NoValue - # a condition variable for concurrent access + def __init__(self, value=NoValue): + try: + Var._count_lock.acquire() + self.name = str(Var._vcount) + finally: + Var._count_lock.release() + Var._vcount += 1 + self._val = value + # a condition variable for Wait self._value_condition = threading.Condition() + # for WaitNeeded self._need_condition = threading.Condition() # value accessors def _set_val(self, val): - self._value_condition.acquire() - try: - if self._val != NoValue: - if val != self._val: - raise AlreadyBound(self, val) - self._val = val - self._value_condition.notifyAll() - finally: - self._value_condition.release() + if self._val != NoValue: + if val != self._val: + raise AlreadyBound(self, val) + self._val = val def _get_val(self): return self._val @@ -62,8 +58,8 @@ def __str__(self): if self.is_bound(): - return "%s = %s" % (self.name, self.val) - return "%s" % self.name + return "<%s>" % str(self._val) + return "" % self.name def __repr__(self): return self.__str__() @@ -73,9 +69,17 @@ def is_bound(self): return self.val != NoValue + def is_free(self): + return not self.isbound() + def bind(self, val): - self.val = val - + self._value_condition.acquire() + try: + self.val = val + self._value_condition.notifyAll() + finally: + self._value_condition.release() + def wait(self): try: self._need_condition.acquire() @@ -101,11 +105,39 @@ finally: self._need_condition.release() -class CsVar(SimpleVar): +var = Var + +#-- utility --------- + +def stream_repr(*args): + """represent streams of variables whose + last element might be unbound""" + repr_ = [] + for S in args: + while S.is_bound(): + v = S.val + if isinstance(v, tuple): + v0 = v[0] + if v0.is_bound(): + repr_ += [str(v0.val), '|'] + else: repr_ += [str(v0), '|'] + S = v[1] + else: + repr_.append(str(v)) + break + else: + repr_.append(str(S)) + repr_.append(' ') + repr_.pop() + return ''.join(repr_) + +#-- to be killed soon ---- + +class CsVar(Var): """Dataflow variable linked to a space""" def __init__(self, name, cs): - SimpleVar.__init__(self) + Var.__init__(self) if name in cs.names: raise AlreadyInStore(name) self.name = name @@ -157,3 +189,4 @@ self._cs.bind(self, val) is_bound = _is_bound + From ac at codespeak.net Tue Mar 14 17:19:56 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 14 Mar 2006 17:19:56 +0100 (CET) Subject: [pypy-svn] r24362 - in pypy/dist/pypy: interpreter module/__builtin__ translator Message-ID: <20060314161956.D5A9010092@code0.codespeak.net> Author: ac Date: Tue Mar 14 17:19:55 2006 New Revision: 24362 Modified: pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/mixedmodule.py pypy/dist/pypy/interpreter/module.py pypy/dist/pypy/interpreter/pycode.py pypy/dist/pypy/module/__builtin__/__init__.py pypy/dist/pypy/module/__builtin__/app_misc.py pypy/dist/pypy/module/__builtin__/operation.py pypy/dist/pypy/translator/geninterplevel.py Log: (pedronis, arre) Create a space helper for interning strings and use it for names, mostly in code objects. => Slight performace improvement in pystone and richards. Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Tue Mar 14 17:19:55 2006 @@ -127,6 +127,7 @@ self.options.usemodules = usemodules self.options.translating = translating self.options.geninterp = geninterp + self.interned_strings = {} self.setoptions(**kw) self.initialize() @@ -376,6 +377,14 @@ else: return self.w_False + def new_interned_str(self, s): + try: + return self.interned_strings[s] + except KeyError: + pass + w_s = self.interned_strings[s] = self.wrap(s) + return w_s + # support for the deprecated __getslice__, __setslice__, __delslice__ def getslice(self, w_obj, w_start, w_stop): w_slice = self.newslice(w_start, w_stop, self.w_None) Modified: pypy/dist/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/dist/pypy/interpreter/mixedmodule.py (original) +++ pypy/dist/pypy/interpreter/mixedmodule.py Tue Mar 14 17:19:55 2006 @@ -30,8 +30,9 @@ w_builtin = self.get(name) return self.space.call_function(w_builtin, *args_w) - def getdictvalue(self, space, name): - w_value = space.finditem(self.w_dict, space.wrap(name)) + def getdictvalue(self, space, name): + w_name = space.new_interned_str(name) + w_value = space.finditem(self.w_dict, w_name) if self.lazy and w_value is None: try: loader = self.loaders[name] @@ -51,7 +52,7 @@ bltin.w_module = self.w_name func._builtinversion_ = bltin w_value = space.wrap(bltin) - space.setitem(self.w_dict, space.wrap(name), w_value) + space.setitem(self.w_dict, w_name, w_value) return w_value def getdict(self): @@ -59,7 +60,7 @@ space = self.space for name in self.loaders: w_value = self.get(name) - space.setitem(self.w_dict, space.wrap(name), w_value) + space.setitem(self.w_dict, space.new_interned_str(name), w_value) self.lazy = False return self.w_dict Modified: pypy/dist/pypy/interpreter/module.py ============================================================================== --- pypy/dist/pypy/interpreter/module.py (original) +++ pypy/dist/pypy/interpreter/module.py Tue Mar 14 17:19:55 2006 @@ -14,7 +14,7 @@ self.w_dict = w_dict self.w_name = w_name if w_name is not None: - space.setitem(w_dict, space.wrap('__name__'), w_name) + space.setitem(w_dict, space.new_interned_str('__name__'), w_name) def setup_after_space_initialization(self): """NOT_RPYTHON: to allow built-in modules to do some more setup @@ -33,5 +33,5 @@ self.w_name = w_name if w_doc is None: w_doc = space.w_None - space.setitem(self.w_dict, space.wrap('__name__'), w_name) - space.setitem(self.w_dict, space.wrap('__doc__'), w_doc) + space.setitem(self.w_dict, space.new_interned_str('__name__'), w_name) + space.setitem(self.w_dict, space.new_interned_str('__doc__'), w_doc) Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Tue Mar 14 17:19:55 2006 @@ -95,7 +95,7 @@ self.co_flags = flags self.co_code = code self.co_consts_w = consts - self.co_names_w = [space.wrap(aname) for aname in names] + self.co_names_w = [space.new_interned_str(aname) for aname in names] self.co_varnames = varnames self.co_freevars = freevars self.co_cellvars = cellvars Modified: pypy/dist/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/__init__.py (original) +++ pypy/dist/pypy/module/__builtin__/__init__.py Tue Mar 14 17:19:55 2006 @@ -50,7 +50,6 @@ 'complex' : 'app_complex.complex', - 'intern' : 'app_misc.intern', 'buffer' : 'app_buffer.buffer', 'reload' : 'app_misc.reload', @@ -105,6 +104,7 @@ 'hash' : 'operation.hash', 'id' : 'operation.id', '_seqiter' : 'operation._seqiter', + 'intern' : 'operation.intern', 'compile' : 'compiling.compile', 'eval' : 'compiling.eval', @@ -112,7 +112,6 @@ '__import__' : 'importing.importhook', 'range' : 'functional.range_int', - # float->string helper '_formatd' : 'special._formatd' } Modified: pypy/dist/pypy/module/__builtin__/app_misc.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/app_misc.py (original) +++ pypy/dist/pypy/module/__builtin__/app_misc.py Tue Mar 14 17:19:55 2006 @@ -3,13 +3,6 @@ """ -_stringtable = {} -def intern(s): - # XXX CPython has also non-immortal interned strings - if not type(s) is str: - raise TypeError("intern() argument 1 must be string.") - return _stringtable.setdefault(s,s) - def find_module(fullname, path): import sys meta_path = sys.meta_path Modified: pypy/dist/pypy/module/__builtin__/operation.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/operation.py (original) +++ pypy/dist/pypy/module/__builtin__/operation.py Tue Mar 14 17:19:55 2006 @@ -159,3 +159,8 @@ def setattr(space, w_object, w_name, w_val): space.setattr(w_object, w_name, w_val) return space.w_None + +def intern(space, w_str): + if space.is_w(space.type(w_str), space.w_str): + return space.new_interned_str(space.str_w(w_str)) + raise OperationError(space.w_TypeError, space.wrap("intern() argument 1 must be string.")) Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 14 17:19:55 2006 @@ -560,9 +560,9 @@ namestr = "_emptystr_" name = self.uniquename('gs_' + namestr[:32]) if len(value) < 30 and "\n" not in value: - txt = '%s = space.wrap(%r)' % (name, value) + txt = '%s = space.new_interned_str(%r)' % (name, value) else: - txt = render_docstr(value, '%s = space.wrap(\n' % name, ')') + txt = render_docstr(value, '%s = space.new_interned_str(\n' % name, ')') txt = txt, # not splitted self.initcode.append(txt) return name @@ -939,11 +939,11 @@ # property is lazy loaded app-level as well, trigger it*s creation self.initcode.append1('space.builtin.get("property") # pull it in') globname = self.nameof(self.moddict) - self.initcode.append('space.setitem(%s, space.wrap("__builtins__"), ' + self.initcode.append('space.setitem(%s, space.new_interned_str("__builtins__"), ' 'space.builtin.w_dict)' % globname) self.initcode.append('%s = space.eval("property(%s)", %s, %s)' %( name, origin, globname, globname) ) - self.initcode.append('space.delitem(%s, space.wrap("__builtins__"))' + self.initcode.append('space.delitem(%s, space.new_interned_str("__builtins__"))' % globname) return name @@ -1039,7 +1039,7 @@ # make sure it is not rendered again key = Constant(doc).key self.rpynames[key] = "w__doc__" - self.initcode.append("w__doc__ = space.wrap(__doc__)") + self.initcode.append("w__doc__ = space.new_interned_str(__doc__)") # info.entrypoint must be done *after* __doc__ is handled, # because nameof(entrypoint) might touch __doc__ early. From mwh at codespeak.net Tue Mar 14 17:23:04 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Mar 2006 17:23:04 +0100 (CET) Subject: [pypy-svn] r24363 - in pypy/extradoc/talk: accu2006 accu2006/accu-2006.key accu2006/accu-2006.key/Contents accu2006/accu-2006.key/thumbs pycon2006 pycon2006/pypy-selfcontained-3.key pycon2006/pypy-selfcontained-3.key/thumbs sprint-introduction.key sprint-introduction.key/thumbs Message-ID: <20060314162304.8CFC610092@code0.codespeak.net> Author: mwh Date: Tue Mar 14 17:22:28 2006 New Revision: 24363 Added: pypy/extradoc/talk/accu2006/ pypy/extradoc/talk/accu2006/accu-2006.key/ pypy/extradoc/talk/accu2006/accu-2006.key/.typeAttributes.dict pypy/extradoc/talk/accu2006/accu-2006.key/Contents/ pypy/extradoc/talk/accu2006/accu-2006.key/Contents/PkgInfo pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-bullets.pdf (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-h.pdf pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-v.pdf (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/index.apxl.gz (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/py-web1.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/ pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-0.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-10.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-11.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-12.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-13.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-14.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-15.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-16.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-17.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-28.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-33.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-4.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-9.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st0-1.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st1-1.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st12-1.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st2.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-1.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-2.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-3.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-4.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-5.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st4.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st5.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st6.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-3.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-5.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-6.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-7.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-8.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7.tiff (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_blue.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_gray.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_green.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_purple.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_red.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_yellow.jpg (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/zban.png (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/zor.png (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.key/zpeach.png (contents, props changed) pypy/extradoc/talk/accu2006/accu-2006.pdf (contents, props changed) Modified: pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.key/index.apxl.gz pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.key/thumbs/st0.tiff pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.pdf pypy/extradoc/talk/sprint-introduction.key/index.apxl.gz pypy/extradoc/talk/sprint-introduction.key/thumbs/st10.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st17.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st27.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st3-5.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st30.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st8.tiff pypy/extradoc/talk/sprint-introduction.key/thumbs/st9.tiff Log: am initial version of my talk for the ACCU conference in a month or so. i would definitely apprieciate a read through and ideas on what else I should talk about (i'd like to talk about the rtyper and low level helpers and using python to write a gc, but there's quite a lot of ground to cover before you can get to that sort of thing). Added: pypy/extradoc/talk/accu2006/accu-2006.key/.typeAttributes.dict ============================================================================== Added: pypy/extradoc/talk/accu2006/accu-2006.key/Contents/PkgInfo ============================================================================== --- (empty file) +++ pypy/extradoc/talk/accu2006/accu-2006.key/Contents/PkgInfo Tue Mar 14 17:22:28 2006 @@ -0,0 +1 @@ +???????? \ No newline at end of file Added: pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-bullets.pdf ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-h.pdf ============================================================================== Files (empty file) and pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-h.pdf Tue Mar 14 17:22:28 2006 differ Added: pypy/extradoc/talk/accu2006/accu-2006.key/White_photo-v.pdf ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/index.apxl.gz ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/py-web1.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-0.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-10.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-11.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-12.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-13.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-14.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-15.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-16.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-17.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-28.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-33.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-4.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/mt0-9.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st0-1.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st1-1.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st12-1.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st2.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-1.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-2.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-3.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-4.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3-5.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st3.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st4.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st5.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st6.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-3.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-5.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-6.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-7.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7-8.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/thumbs/st7.tiff ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_blue.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_gray.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_green.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_purple.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_red.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/tile_paper_yellow.jpg ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/zban.png ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/zor.png ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.key/zpeach.png ============================================================================== Binary file. No diff available. Added: pypy/extradoc/talk/accu2006/accu-2006.pdf ============================================================================== Binary file. No diff available. Modified: pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.key/index.apxl.gz ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.key/thumbs/st0.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/pycon2006/pypy-selfcontained-3.pdf ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/index.apxl.gz ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st10.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st17.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st27.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st3-5.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st30.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st8.tiff ============================================================================== Binary files. No diff available. Modified: pypy/extradoc/talk/sprint-introduction.key/thumbs/st9.tiff ============================================================================== Binary files. No diff available. From ac at codespeak.net Tue Mar 14 17:26:12 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 14 Mar 2006 17:26:12 +0100 (CET) Subject: [pypy-svn] r24364 - pypy/dist/pypy/translator/c Message-ID: <20060314162612.DF01A10092@code0.codespeak.net> Author: ac Date: Tue Mar 14 17:26:12 2006 New Revision: 24364 Modified: pypy/dist/pypy/translator/c/genc.py Log: (pedronis, arre) Enable HAVE___THREAD only for standalone targets. We have seen it triggering obscure bugs when used with many dynamic libraries. Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Tue Mar 14 17:26:12 2006 @@ -75,8 +75,6 @@ # defines={'COUNT_OP_MALLOCS': 1} if CBuilder.have___thread is None: CBuilder.have___thread = check_under_under_thread() - if CBuilder.have___thread: - defines['HAVE___THREAD'] = 1 if not self.standalone: from pypy.translator.c.symboltable import SymbolTable self.symboltable = SymbolTable() @@ -85,6 +83,8 @@ exports = {self.entrypoint.func_name: pf}, symboltable = self.symboltable) else: + if CBuilder.have___thread: + defines['HAVE___THREAD'] = 1 if self.stackless: defines['USE_STACKLESS'] = '1' defines['USE_OPTIMIZED_STACKLESS_UNWIND'] = '1' From ac at codespeak.net Tue Mar 14 18:53:34 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 14 Mar 2006 18:53:34 +0100 (CET) Subject: [pypy-svn] r24365 - in pypy/dist/pypy: bin interpreter module/sys objspace objspace/std Message-ID: <20060314175334.CA26210093@code0.codespeak.net> Author: ac Date: Tue Mar 14 18:53:32 2006 New Revision: 24365 Modified: pypy/dist/pypy/bin/py.py pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/main.py pypy/dist/pypy/interpreter/mixedmodule.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/module/sys/__init__.py pypy/dist/pypy/objspace/descroperation.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/typeobject.py pypy/dist/pypy/objspace/std/typetype.py Log: (pedronis, arre) Refactor to avoid unwrapping and re-wrapping of strings when accessing attributes. Modified: pypy/dist/pypy/bin/py.py ============================================================================== --- pypy/dist/pypy/bin/py.py (original) +++ pypy/dist/pypy/bin/py.py Tue Mar 14 18:53:32 2006 @@ -130,7 +130,7 @@ exit_status = 0 finally: # call the sys.exitfunc() - w_exitfunc = space.sys.getdictvalue(space, 'exitfunc') + w_exitfunc = space.sys.getdictvalue_w(space, 'exitfunc') if w_exitfunc is not None: def doit(): space.call_function(w_exitfunc) Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Tue Mar 14 18:53:32 2006 @@ -16,10 +16,13 @@ def getdict(self): return None - def getdictvalue(self, space, attr): + def getdictvalue_w(self, space, attr): + return self.getdictvalue(space, space.wrap(attr)) + + def getdictvalue(self, space, w_attr): w_dict = self.getdict() if w_dict is not None: - return space.finditem(w_dict, space.wrap(attr)) + return space.finditem(w_dict, w_attr) return None def setdict(self, space, w_dict): @@ -363,6 +366,10 @@ """shortcut for space.int_w(space.hash(w_obj))""" return self.int_w(self.hash(w_obj)) + def set_str_keyed_item(self, w_obj, w_key, w_value): + w_strkey = self.wrap(self.str_w(w_key)) # Force the key to a space.w_str + return self.setitem(w_obj, w_strkey, w_value) + def finditem(self, w_obj, w_key): try: return self.getitem(w_obj, w_key) @@ -533,7 +540,7 @@ w_type = self.type(w_obj) w_mro = self.getattr(w_type, self.wrap("__mro__")) for w_supertype in self.unpackiterable(w_mro): - w_value = w_supertype.getdictvalue(self, name) + w_value = w_supertype.getdictvalue_w(self, name) if w_value is not None: return w_value return None Modified: pypy/dist/pypy/interpreter/main.py ============================================================================== --- pypy/dist/pypy/interpreter/main.py (original) +++ pypy/dist/pypy/interpreter/main.py Tue Mar 14 18:53:32 2006 @@ -126,11 +126,11 @@ w_traceback) # call sys.excepthook if present - w_hook = space.sys.getdictvalue(space, 'excepthook') + w_hook = space.sys.getdictvalue_w(space, 'excepthook') if w_hook is not None: # hack: skip it if it wasn't modified by the user, # to do instead the faster verbose/nonverbose thing below - w_original = space.sys.getdictvalue(space, '__excepthook__') + w_original = space.sys.getdictvalue_w(space, '__excepthook__') if w_original is None or not space.is_w(w_hook, w_original): space.call_function(w_hook, w_type, w_value, w_traceback) return False # done Modified: pypy/dist/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/dist/pypy/interpreter/mixedmodule.py (original) +++ pypy/dist/pypy/interpreter/mixedmodule.py Tue Mar 14 18:53:32 2006 @@ -21,7 +21,7 @@ def get(self, name): space = self.space - w_value = self.getdictvalue(space, name) + w_value = self.getdictvalue_w(space, name) if w_value is None: raise OperationError(space.w_AttributeError, space.wrap(name)) return w_value @@ -30,10 +30,11 @@ w_builtin = self.get(name) return self.space.call_function(w_builtin, *args_w) - def getdictvalue(self, space, name): - w_name = space.new_interned_str(name) + def getdictvalue(self, space, w_name): w_value = space.finditem(self.w_dict, w_name) if self.lazy and w_value is None: + name = space.str_w(w_name) + w_name = space.new_interned_str(name) try: loader = self.loaders[name] except KeyError: Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Tue Mar 14 18:53:32 2006 @@ -472,9 +472,9 @@ w_value = f.space.finditem(f.w_globals, w_varname) if w_value is None: # not in the globals, now look in the built-ins - varname = f.getname_u(nameindex) - w_value = f.builtin.getdictvalue(f.space, varname) + w_value = f.builtin.getdictvalue(f.space, w_varname) if w_value is None: + varname = f.getname_u(nameindex) message = "global name '%s' is not defined" % varname raise OperationError(f.space.w_NameError, f.space.wrap(message)) @@ -559,7 +559,7 @@ w_modulename = f.getname_w(nameindex) modulename = f.space.str_w(w_modulename) w_fromlist = f.valuestack.pop() - w_import = f.builtin.getdictvalue(f.space, '__import__') + w_import = f.builtin.getdictvalue_w(f.space, '__import__') if w_import is None: raise OperationError(space.w_ImportError, space.wrap("__import__ not found")) Modified: pypy/dist/pypy/module/sys/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys/__init__.py (original) +++ pypy/dist/pypy/module/sys/__init__.py Tue Mar 14 18:53:32 2006 @@ -96,11 +96,12 @@ w_modules = self.get('modules') self.space.setitem(w_modules, w_name, w_module) - def getdictvalue(self, space, attr): + def getdictvalue(self, space, w_attr): """ specialize access to dynamic exc_* attributes. """ - value = MixedModule.getdictvalue(self, space, attr) + value = MixedModule.getdictvalue(self, space, w_attr) if value is not None: - return value + return value + attr = space.str_w(w_attr) if attr == 'exc_type': operror = space.getexecutioncontext().sys_exc_info() if operror is None: Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Tue Mar 14 18:53:32 2006 @@ -20,7 +20,7 @@ if w_descr is not None: if space.is_data_descr(w_descr): return space.get(w_descr, w_obj) - w_value = w_obj.getdictvalue(space, name) + w_value = w_obj.getdictvalue(space, w_name) if w_value is not None: return w_value if w_descr is not None: @@ -39,7 +39,7 @@ # note: don't use w_name as a key in w_dict directly -- the expected # result of setattr() is that it never stores subclasses of 'str' # in the __dict__ - space.setitem(w_dict, space.wrap(name), w_value) + space.set_str_keyed_item(w_dict, w_name, w_value) return raiseattrerror(space, w_obj, name, w_descr) Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Tue Mar 14 18:53:32 2006 @@ -436,6 +436,15 @@ else: return ObjSpace.finditem(self, w_obj, w_key) + def set_str_keyed_item(self, w_obj, w_key, w_value): + # performance shortcut to avoid creating the OperationError(KeyError) + if type(w_key) is not W_StringObject: + w_key = self.new_interned_str(self.str_w(w_key)) + if type(w_obj) is W_DictObject: + w_obj.content[w_key] = w_value + else: + self.setitem(w_obj, w_key, w_value) + # support for the deprecated __getslice__, __setslice__, __delslice__ def getslice(self, w_obj, w_start, w_stop): Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Tue Mar 14 18:53:32 2006 @@ -168,6 +168,8 @@ else: # create member slot_name = _mangle(slot_name, name) + # Force interning of slot names. + slot_name = space.str_w(space.new_interned_str(slot_name)) w_self.dict_w[slot_name] = space.wrap(Member(nslots, slot_name, w_self)) nslots += 1 @@ -212,12 +214,16 @@ if isinstance(w_new, Function): w_self.dict_w['__new__'] = StaticMethod(w_new) - def getdictvalue(w_self, space, attr): + def getdictvalue(w_self, space, w_attr): + return w_self.getdictvalue_w(space, space.str_w(w_attr)) + + def getdictvalue_w(w_self, space, attr): try: return w_self.dict_w[attr] except KeyError: if w_self.lazyloaders: if attr in w_self.lazyloaders: + w_attr = space.new_interned_str(attr) loader = w_self.lazyloaders[attr] del w_self.lazyloaders[attr] w_value = loader() @@ -230,7 +236,7 @@ # note that this doesn't call __get__ on the result at all space = w_self.space for w_class in w_self.mro_w: - w_value = w_class.getdictvalue(space, key) + w_value = w_class.getdictvalue_w(space, key) if w_value is not None: return w_value return None @@ -240,7 +246,7 @@ # attribute was found space = w_self.space for w_class in w_self.mro_w: - w_value = w_class.getdictvalue(space, key) + w_value = w_class.getdictvalue_w(space, key) if w_value is not None: return w_class, w_value return None, None @@ -265,7 +271,7 @@ "NOT_RPYTHON. Forces the lazy attributes to be computed." if 'lazyloaders' in w_self.__dict__: for attr in w_self.lazyloaders.keys(): - w_self.getdictvalue(w_self.space, attr) + w_self.getdictvalue_w(w_self.space, attr) del w_self.lazyloaders return False Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Tue Mar 14 18:53:32 2006 @@ -103,7 +103,7 @@ return space.wrap("""type(object) -> the object's type type(name, bases, dict) -> a new type""") w_type = _check(space, w_type) - w_result = w_type.getdictvalue(space, '__doc__') + w_result = w_type.getdictvalue_w(space, '__doc__') if w_result is None: return space.w_None else: From cfbolz at codespeak.net Tue Mar 14 19:00:24 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 14 Mar 2006 19:00:24 +0100 (CET) Subject: [pypy-svn] r24366 - in pypy/dist/pypy/translator: . backendopt backendopt/test Message-ID: <20060314180024.3757810094@code0.codespeak.net> Author: cfbolz Date: Tue Mar 14 19:00:17 2006 New Revision: 24366 Modified: pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/backendopt/test/test_inline.py pypy/dist/pypy/translator/simplify.py Log: make inlining and one of the simplifications used by inlining do the right thing wrt cleanups. this should make it possible to use inlining together with push/pop of roots in the gcs soon. Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Tue Mar 14 19:00:17 2006 @@ -93,6 +93,7 @@ self.varmap = {} self.beforeblock = block self._copied_blocks = {} + self._copied_cleanups = {} self.op = block.operations[index_operation] self.graph_to_inline = self.op.args[0].value._obj.graph self.exception_guarded = False @@ -125,7 +126,24 @@ def copy_operation(self, op): args = [self.get_new_name(arg) for arg in op.args] - return SpaceOperation(op.opname, args, self.get_new_name(op.result)) + result = SpaceOperation(op.opname, args, self.get_new_name(op.result)) + if getattr(op, "cleanup", None) is not None: + result.cleanup = self.copy_cleanup(op.cleanup) + return result + + def copy_cleanup(self, cleanup): + if cleanup in self._copied_cleanups: + return self._copied_cleanups[cleanup] + finallyops, exceptops = cleanup + copyfinallyops = [] + for op in finallyops: + copyfinallyops.append(self.copy_operation(op)) + copyexceptops = [] + for op in exceptops: + copyexceptops.append(self.copy_operation(op)) + copycleanup = (tuple(copyfinallyops), tuple(copyexceptops)) + self._copied_cleanups[cleanup] = copycleanup + return copycleanup def copy_block(self, block): if block in self._copied_blocks: Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_inline.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_inline.py Tue Mar 14 19:00:17 2006 @@ -401,7 +401,7 @@ ggraph.startblock.operations[0].cleanup = cleanup py.test.raises(CannotInline, inline_function, t, f, ggraph) -def DONOTtest_inline_copies_cleanups(): +def test_inline_copies_cleanups(): from pypy.objspace.flow.model import Variable, SpaceOperation, Constant from pypy.rpython.lltypesystem.lltype import Signed import math @@ -419,6 +419,6 @@ cleanup = ((cleanupop, ), (cleanupop, )) graph.startblock.operations[0].cleanup = cleanup inline_function(t, f, ggraph) - assert ggraph.startblock.operations[0].cleanup == cleanup - if option.view: + if option.view: t.view() + assert hasattr(ggraph.startblock.operations[0], "cleanup") Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Tue Mar 14 19:00:17 2006 @@ -300,14 +300,27 @@ len(entrymap[link.target]) == 1 and link.target.exits): # stop at the returnblock renaming = {} + cache_cleanups = {} for vprev, vtarg in zip(link.args, link.target.inputargs): renaming[vtarg] = vprev def rename(v): return renaming.get(v, v) - for op in link.target.operations: + def rename_op(op): args = [rename(a) for a in op.args] - op = SpaceOperation(op.opname, args, rename(op.result)) - link.prevblock.operations.append(op) + if getattr(op, "cleanup", None) is not None: + if op.cleanup not in cache_cleanups: + finallyops, exceptops = op.cleanup + cleanup = (tuple([rename_op(fo) for fo in finallyops]), + tuple([rename_op(eo) for eo in exceptops])) + cache_cleanups[op.cleanup] = cleanup + else: + cleanup = cache_cleanups[op.cleanup] + op = SpaceOperation(op.opname, args, rename(op.result), cleanup=cleanup) + else: + op = SpaceOperation(op.opname, args, rename(op.result)) + return op + for op in link.target.operations: + link.prevblock.operations.append(rename_op(op)) exits = [] for exit in link.target.exits: newexit = exit.copy(rename) From cfbolz at codespeak.net Tue Mar 14 20:22:58 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 14 Mar 2006 20:22:58 +0100 (CET) Subject: [pypy-svn] r24368 - in pypy/dist/pypy: rpython/memory translator translator/backendopt Message-ID: <20060314192258.1B56310093@code0.codespeak.net> Author: cfbolz Date: Tue Mar 14 20:22:54 2006 New Revision: 24368 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/simplify.py Log: inline push/pop of the roots and malloc in the gctransformer when possible Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Tue Mar 14 20:22:54 2006 @@ -35,13 +35,15 @@ class GCTransformer(object): finished = False - def __init__(self, translator): + def __init__(self, translator, inline=False): self.translator = translator self.seen_graphs = {} if translator: self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) else: self.mixlevelannotator = None + self.inline = inline + self.graphs_to_inline = {} def get_lltype_of_exception_value(self): if self.translator is not None and self.translator.rtyper is not None: @@ -78,6 +80,13 @@ v = Variable('vanishing_exc_value') v.concretetype = self.get_lltype_of_exception_value() graph.exc_cleanup = (v, self.pop_alive(v)) + if self.inline: + from pypy.translator.backendopt import inline + for inline_graph in self.graphs_to_inline: + try: + inline.inline_function(self.translator, inline_graph, graph) + except inline.CannotInline: + pass def transform_block(self, block): newops = [] @@ -545,8 +554,8 @@ class BoehmGCTransformer(GCTransformer): gc_header_offset = gc.GCHeaderOffset(lltype.Void) - def __init__(self, translator): - super(BoehmGCTransformer, self).__init__(translator) + def __init__(self, translator, inline=False): + super(BoehmGCTransformer, self).__init__(translator, inline=inline) self.finalizer_funcptrs = {} def push_alive_nopyobj(self, var): @@ -647,7 +656,7 @@ class FrameworkGCTransformer(BoehmGCTransformer): def __init__(self, translator): - super(FrameworkGCTransformer, self).__init__(translator) + super(FrameworkGCTransformer, self).__init__(translator, inline=True) class GCData(object): from pypy.rpython.memory.gc import MarkSweepGC as GCClass startheapsize = 640*1024 # XXX adjust @@ -791,8 +800,11 @@ self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph, attach_empty_cleanup=True) self.push_root_ptr = self.graph2funcptr(push_root_graph) + self.graphs_to_inline[push_root_graph] = True self.pop_root_ptr = self.graph2funcptr(pop_root_graph) + self.graphs_to_inline[pop_root_graph] = True self.malloc_ptr = self.graph2funcptr(malloc_graph, True) + self.graphs_to_inline[malloc_graph] = True def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Tue Mar 14 20:22:54 2006 @@ -62,7 +62,9 @@ raise CannotInline("inlining a recursive function") operation = block.operations[index_operation] if getattr(operation, "cleanup", None) is not None: - raise CannotInline("cannot inline a function with cleanup attached") + finallyops, exceptops = operation.cleanup + if finallyops or exceptops: + raise CannotInline("cannot inline a function with cleanup attached") _inline_function(translator, graph, block, index_operation) checkgraph(graph) count += 1 @@ -132,6 +134,8 @@ return result def copy_cleanup(self, cleanup): + if cleanup is None: + return None if cleanup in self._copied_cleanups: return self._copied_cleanups[cleanup] finallyops, exceptops = cleanup Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Tue Mar 14 20:22:54 2006 @@ -307,8 +307,10 @@ return renaming.get(v, v) def rename_op(op): args = [rename(a) for a in op.args] - if getattr(op, "cleanup", None) is not None: - if op.cleanup not in cache_cleanups: + if hasattr(op, "cleanup"): + if op.cleanup is None: + cleanup = None + elif op.cleanup not in cache_cleanups: finallyops, exceptops = op.cleanup cleanup = (tuple([rename_op(fo) for fo in finallyops]), tuple([rename_op(eo) for eo in exceptops])) From nik at codespeak.net Tue Mar 14 22:04:26 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 14 Mar 2006 22:04:26 +0100 (CET) Subject: [pypy-svn] r24369 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060314210426.0C82610091@code0.codespeak.net> Author: nik Date: Tue Mar 14 22:04:26 2006 New Revision: 24369 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: pycon sprint report day 1. corrections welcome ... Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Tue Mar 14 22:04:26 2006 @@ -14,7 +14,40 @@ what we'd be working on for the rest of the day. This plan went out the window fairly quickly though, for a variety of -reasons... +reasons... (?) + +Armin and three PyPy newcomers -- Mick, Gene and Joshua -- dived into +the ever popular rctypes. They made annotation work for all ctypes +types and cleaned up bits and pieces. Along the way, they also started +implementing a new registry mechanism for external functions, aiming +at getting rid of the approximately 42 steps required to add a new +external function. + +The two Canadian newcomers -- Stuart and Martin -- got introduced to +PyPy by Arre, implementing the new 2.5 builtins any() and all(). +They proceeded with implementing the new with keyword (PEP 308), +which despite some parser/compiler hairyness apparently went quite +smoothly. + +Anders L. and George took a tour the logic programming facilities in +PyPy and worked on a Sudoku solver using the computation space. But +they were slowed down quite a bit by bugs. The code was not checked +in until after the sprint. + +Richard and Pat -- who was hooked on PyPy at the last PyCon sprint -- +hacked the LLVM backend back into shape (it was broken due to ongoing +work in the GC area). Various compatibility issues with LLVM versions +were also tackled. + +Samuele and Nik picked up the lately neglected ootypesystem and +ported PBC tests over from lltypesystem, fixing various loose ends +like __init__ and keyword arguments support. + +Let's not forget the py.lib sub-sprint happening in the same room as +the PyPy sprint, starring Holger, Jan and Brian. Unfortunately the +Texas Mystery Disease was making the rounds in the py.lib team, both +Holger and Brian weren't feeling well, so there was only little +progress generally improving win32 support of the py.lib. Day 2 ----- From nik at codespeak.net Tue Mar 14 22:54:37 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 14 Mar 2006 22:54:37 +0100 (CET) Subject: [pypy-svn] r24371 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060314215437.9C6CD10091@code0.codespeak.net> Author: nik Date: Tue Mar 14 22:54:36 2006 New Revision: 24371 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: pycon sprint report day 4 (because that was the easiest one ...) Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Tue Mar 14 22:54:36 2006 @@ -65,4 +65,19 @@ Day 4 ----- -XXX Did enough work get done on Thursday to even bother mentioning it? +The sprinters who had lasted this long were mostly in shutdown mode +already, with many of them flying out in the afternoon. There wasn't +any formal planning meeting. Some code was written anyway. Armin +worked on SpaceOperation.cleanup; Gene and Armin on rctypes +specialization; Samuele and Nik on __del__ support for ootypesystem; +Arre, Anders L. and Stuart on making parser/compiler translatable +again; and Richard on running LLVM tests with the isolate tool. + +Most people left during the afternoon. The remaining handful hung +out at the hotel pool and were later joined by people from other +sprints for a beer and pizza happening. The PyCon organizers even +pointed a wireless router from one of their hotel rooms at the pool, +for those who couldn't stop sprinting even at 9 pm, lying in a deck +chair, typing single-handedly since one hand was clasping a beer ... + +We'll be back next year! From nik at codespeak.net Wed Mar 15 09:31:13 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 15 Mar 2006 09:31:13 +0100 (CET) Subject: [pypy-svn] r24375 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060315083113.90FA41008E@code0.codespeak.net> Author: nik Date: Wed Mar 15 09:31:11 2006 New Revision: 24375 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: fix factual error Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Wed Mar 15 09:31:11 2006 @@ -25,8 +25,8 @@ The two Canadian newcomers -- Stuart and Martin -- got introduced to PyPy by Arre, implementing the new 2.5 builtins any() and all(). -They proceeded with implementing the new with keyword (PEP 308), -which despite some parser/compiler hairyness apparently went quite +They proceeded with implementing conditional expressions which +despite some parser/compiler hairyness apparently went quite smoothly. Anders L. and George took a tour the logic programming facilities in From mwh at codespeak.net Wed Mar 15 10:47:36 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 15 Mar 2006 10:47:36 +0100 (CET) Subject: [pypy-svn] r24376 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060315094736.9CE4F10089@code0.codespeak.net> Author: mwh Date: Wed Mar 15 10:47:35 2006 New Revision: 24376 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: small language + fact fixes Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Wed Mar 15 10:47:35 2006 @@ -13,41 +13,37 @@ planning session, where we divided up into pairs or threes and decided what we'd be working on for the rest of the day. -This plan went out the window fairly quickly though, for a variety of -reasons... (?) - Armin and three PyPy newcomers -- Mick, Gene and Joshua -- dived into -the ever popular rctypes. They made annotation work for all ctypes -types and cleaned up bits and pieces. Along the way, they also started -implementing a new registry mechanism for external functions, aiming -at getting rid of the approximately 42 steps required to add a new -external function. +the ever popular rctypes. They worked on annotation for all ctypes +types. This turned out to involve implementing a new registry +mechanism for external functions, which also will let us eliminate +some of the approximately 42 steps required to add a new external +function. The two Canadian newcomers -- Stuart and Martin -- got introduced to -PyPy by Arre, implementing the new 2.5 builtins any() and all(). -They proceeded with implementing conditional expressions which -despite some parser/compiler hairyness apparently went quite -smoothly. - -Anders L. and George took a tour the logic programming facilities in -PyPy and worked on a Sudoku solver using the computation space. But -they were slowed down quite a bit by bugs. The code was not checked -in until after the sprint. - -Richard and Pat -- who was hooked on PyPy at the last PyCon sprint -- -hacked the LLVM backend back into shape (it was broken due to ongoing -work in the GC area). Various compatibility issues with LLVM versions -were also tackled. +PyPy by Arre, implementing the new 2.5 builtins any() and all(). Then +they went on to implementing conditional expressions which, despite +some parser/compiler hairiness, apparently went quite smoothly. + +Anders L. and George took a tour of the logic programming facilities +in PyPy and worked on a Sudoku solver using the computation space, but +they were slowed down quite a bit by bugs. The code was not checked in +until after the sprint. + +Richard and Pat -- who was hooked on PyPy at the Amsterdam sprint back +in 2003 -- hacked the LLVM backend back into shape (it was broken due +to ongoing work in the GC area). Various compatibility issues with +LLVM versions were also tackled. Samuele and Nik picked up the lately neglected ootypesystem and ported PBC tests over from lltypesystem, fixing various loose ends like __init__ and keyword arguments support. -Let's not forget the py.lib sub-sprint happening in the same room as -the PyPy sprint, starring Holger, Jan and Brian. Unfortunately the -Texas Mystery Disease was making the rounds in the py.lib team, both -Holger and Brian weren't feeling well, so there was only little -progress generally improving win32 support of the py.lib. +We should not forget the py.lib sub-sprint happening in the same room +as the PyPy sprint, starring Holger, Jan and Brian. Unfortunately the +Texas Mystery Disease was making the rounds, and both Holger and Brian +weren't feeling well so there was only a little progress, generally +improving the py.lib's story on win32. Day 2 ----- @@ -65,19 +61,19 @@ Day 4 ----- -The sprinters who had lasted this long were mostly in shutdown mode -already, with many of them flying out in the afternoon. There wasn't -any formal planning meeting. Some code was written anyway. Armin -worked on SpaceOperation.cleanup; Gene and Armin on rctypes -specialization; Samuele and Nik on __del__ support for ootypesystem; -Arre, Anders L. and Stuart on making parser/compiler translatable -again; and Richard on running LLVM tests with the isolate tool. - -Most people left during the afternoon. The remaining handful hung -out at the hotel pool and were later joined by people from other -sprints for a beer and pizza happening. The PyCon organizers even -pointed a wireless router from one of their hotel rooms at the pool, -for those who couldn't stop sprinting even at 9 pm, lying in a deck -chair, typing single-handedly since one hand was clasping a beer ... +The sprinters who had lasted this long were mostly in shutdown mode by +now, with many of them flying out in the afternoon. There wasn't any +formal planning meeting. Some code was written anyway: Armin worked on +SpaceOperation.cleanup; Gene and Armin on rctypes specialization; +Samuele and Nik on __del__ support for ootypesystem; Arre, Anders +L. and Stuart on making the parser and compiler translatable again; +and Richard on running LLVM tests with the isolate tool. + +Most people left during the afternoon. The remaining handful hung out +at the hotel pool and were later joined by people from other sprints +for a beer and pizza session. The PyCon organizers even pointed a +wireless router from one of their hotel rooms at the pool, for those +who couldn't stop sprinting even at 9 pm, lying in a deck chair, +typing single-handedly since one hand was clasping a beer ... We'll be back next year! From nik at codespeak.net Wed Mar 15 15:05:15 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Wed, 15 Mar 2006 15:05:15 +0100 (CET) Subject: [pypy-svn] r24385 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060315140515.5B0A21008A@code0.codespeak.net> Author: nik Date: Wed Mar 15 15:05:12 2006 New Revision: 24385 Added: pypy/dist/pypy/translator/squeak/message.py pypy/dist/pypy/translator/squeak/test/test_message.py Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/runtest.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: rename Selector class to Message. move it into its own module. this might actually be refactored away at some later point, but need to keep it around for further refactoring steps. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Wed Mar 15 15:05:12 2006 @@ -1,11 +1,8 @@ import datetime, sys -from pypy.objspace.flow.model import traverse -from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Constant, Variable, Block from pypy.objspace.flow.model import last_exception, checkgraph from pypy.translator.gensupp import NameManager -from pypy.translator.unsimplify import remove_direct_loops -from pypy.translator.simplify import simplify_graph +from pypy.translator.squeak.message import Message, camel_case from pypy.rpython.ootypesystem.ootype import Instance, ROOT from pypy.rpython.rarithmetic import r_int, r_uint from pypy import conftest @@ -123,45 +120,6 @@ return unique -def camel_case(identifier): - identifier = identifier.replace(".", "_") - words = identifier.split('_') - return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) - -class Selector: - - def __init__(self, function_name, arg_count): - self.parts = [camel_case(function_name)] - self.arg_count = arg_count - self.infix = False - if len(self.parts[0]) <= 2 and not self.parts[0].isalnum(): - # Binary infix selector, e.g. "+" - assert arg_count == 1 - self.infix = True - if arg_count > 1: - self.parts += ["with"] * (arg_count - 1) - - def __str__(self): - if self.arg_count == 0 or self.infix: - return self.parts[0] - else: - return "%s:%s" % (self.parts[0], - "".join([p + ":" for p in self.parts[1:]])) - - def symbol(self): - return str(self) - - def signature(self, arg_names): - assert len(arg_names) == self.arg_count - if self.arg_count == 0: - return self.parts[0] - elif self.infix: - return "%s %s" % (self.parts[0], arg_names[0]) - else: - return " ".join(["%s: %s" % (p, a) - for (p, a) in zip(self.parts, arg_names)]) - - class CodeNode: def __hash__(self): @@ -241,10 +199,10 @@ selectormap = { #'setitem:with:': 'at:put:', #'getitem:': 'at:', - 'new': Selector('new', 0), - 'runtimenew': Selector('new', 0), - 'classof': Selector('class', 0), - 'sameAs': Selector('yourself', 0), + 'new': 'new', + 'runtimenew': 'new', + 'classof': 'class', + 'sameAs': 'yourself', } primitive_ops = { @@ -267,13 +225,13 @@ primitive_masks = { # XXX horrendous, but I can't figure out how to do this cleanly - "int": (Selector("maskInt", 1), + "int": (Message("maskInt"), """maskInt: i ((i <= %s) & (i >= %s)) ifTrue: [^i]. ^ i + %s \\\\ %s - %s """ % (sys.maxint, -sys.maxint-1, sys.maxint+1, 2*(sys.maxint+1), sys.maxint+1)), - "uint": (Selector("maskUint", 1), + "uint": (Message("maskUint"), """maskUint: i ^ i bitAnd: %s""" % r_uint.MASK), } @@ -281,7 +239,7 @@ def render_body(self, startblock): self.loops = LoopFinder(startblock).loops args = self.arguments(startblock) - sel = Selector(self.name, len(args)) + sel = Message(self.name) yield sel.signature([self.expr(v) for v in args]) # XXX should declare local variables here @@ -319,7 +277,7 @@ def oper_primitive(self, op, ptype, opname): receiver = self.expr(op.args[0]) args = [self.expr(arg) for arg in op.args[1:]] - sel = Selector(self.primitive_ops[opname], len(args)) + sel = Message(self.primitive_ops[opname]) message = "%s %s" % (receiver, sel.signature(args)) if opname in self.primitive_wrapping_ops \ and self.primitive_masks.has_key(ptype): @@ -330,9 +288,10 @@ return "%s := %s." % (self.expr(op.result), message) def assignment(self, op, receiver_name, sel_name, arg_names): - sel = Selector(sel_name, len(arg_names)) + sel_name = camel_case(sel_name) if op.opname != "oosend": - sel = self.selectormap.get(sel.symbol(), sel) + sel_name = self.selectormap.get(sel_name, sel_name) + sel = Message(sel_name) return "%s := %s %s." % (self.expr(op.result), receiver_name, sel.signature(arg_names)) @@ -555,7 +514,7 @@ yield self.render_fileout_header( self.gen.nameof_Instance(self.INSTANCE), "initializers") fields = self.INSTANCE._allfields() - sel = Selector("field_init", len(fields)) + sel = Message("field_init") arg_names = ["a%s" % i for i in range(len(fields))] yield sel.signature(arg_names) for field_name, arg_name in zip(fields.keys(), arg_names): @@ -581,7 +540,7 @@ def render(self): yield self.render_fileout_header("PyConstants class", "internals") - sel = Selector("setupConstants", 0) + sel = Message("setupConstants") yield sel.signature([]) yield " Constants := Dictionary new." for const, const_id in self.constants.iteritems(): @@ -590,7 +549,7 @@ field_names = INST._allfields().keys() field_values = [self.gen.nameof(getattr(const.value, f)) for f in field_names] - init_sel = Selector("field_init", len(field_values)) + init_sel = Message("field_init") yield " Constants at: '%s' put: (%s new %s)." \ % (const_id, class_name, init_sel.signature(field_values)) @@ -598,7 +557,7 @@ yield "" yield self.render_fileout_header("PyConstants class", "internals") - sel = Selector("getConstant", 1) + sel = Message("getConstant") yield sel.signature(["constId"]) yield " ^ Constants at: constId" yield "! !" Added: pypy/dist/pypy/translator/squeak/message.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/message.py Wed Mar 15 15:05:12 2006 @@ -0,0 +1,38 @@ +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) + +class Message: + + def __init__(self, name): + self.name = camel_case(name) # XXX Should not use camel_case here + self.infix = False + if len(name) <= 2 and not name.isalnum(): + # Binary infix selector, e.g. "+" + self.infix = True + + def _selector_parts(self, arg_count): + parts = [self.name] + if arg_count > 1: + parts += ["with"] * (arg_count - 1) + return parts + + def symbol(self, arg_count): + if arg_count == 0 or self.infix: + return self.name + else: + parts = self._selector_parts(arg_count) + return "%s:%s" % (parts[0], "".join([p + ":" for p in parts[1:]])) + + def signature(self, arg_strings): + if len(arg_strings) == 0: + return self.name + elif self.infix: + assert len(arg_strings) == 1 + return "%s %s" % (self.name, arg_strings[0]) + else: + parts = self._selector_parts(len(arg_strings)) + return " ".join(["%s: %s" % (p, a) + for (p, a) in zip(parts, arg_strings)]) + Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Wed Mar 15 15:05:12 2006 @@ -1,7 +1,8 @@ import os import py from pypy.tool.udir import udir -from pypy.translator.squeak.gensqueak import GenSqueak, Selector +from pypy.translator.squeak.gensqueak import GenSqueak +from pypy.translator.squeak.message import Message from pypy.translator.translator import TranslationContext from pypy import conftest @@ -85,7 +86,7 @@ options = "" cmd = 'squeak %s -- %s %s "%s" %s' \ % (options, startup_st, udir.join(self._gen.filename), - Selector(self._func.__name__, len(args)).symbol(), + Message(self._func.__name__).symbol(len(args)), " ".join(['"%s"' % a for a in args])) squeak_process = os.popen(cmd) result = squeak_process.read() Added: pypy/dist/pypy/translator/squeak/test/test_message.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/test_message.py Wed Mar 15 15:05:12 2006 @@ -0,0 +1,16 @@ +from pypy.translator.squeak.message import Message + +class TestMessage: + + def test_symbol(self): + assert Message("bla_bla").symbol(0) == "blaBla" + assert Message("bla").symbol(1) == "bla:" + assert Message("bla_bla_bla").symbol(3) == "blaBlaBla:with:with:" + assert Message("+").symbol(1) == "+" + + def test_signature(self): + assert Message("bla").signature([]) == "bla" + assert Message("bla").signature(["v"]) == "bla: v" + assert Message("bla").signature(["v0", "v1"]) == "bla: v0 with: v1" + assert Message("+").signature(["v"]) == "+ v" + Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Wed Mar 15 15:05:12 2006 @@ -1,7 +1,6 @@ import os import py from pypy.translator.test import snippet -from pypy.translator.squeak.gensqueak import Selector, camel_case from pypy.translator.squeak.test.runtest import compile_function class TestGenSqueak: @@ -118,18 +117,3 @@ assert fn(1) == "1" assert fn(2) == "2" - -class TestSelector: - - def test_selector(self): - assert Selector("bla_bla", 0).symbol() == "blaBla" - assert Selector("bla", 1).symbol() == "bla:" - assert Selector("bla_bla_bla", 3).symbol() == "blaBlaBla:with:with:" - assert Selector("+", 1).symbol() == "+" - - def test_signature(self): - assert Selector("bla", 0).signature([]) == "bla" - assert Selector("bla", 1).signature(["v"]) == "bla: v" - assert Selector("bla", 2).signature(["v0", "v1"]) == "bla: v0 with: v1" - assert Selector("+", 1).signature(["v"]) == "+ v" - From pedronis at codespeak.net Wed Mar 15 15:40:04 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Mar 2006 15:40:04 +0100 (CET) Subject: [pypy-svn] r24387 - in pypy/dist/pypy/jit: . test Message-ID: <20060315144004.9B9C310093@code0.codespeak.net> Author: pedronis Date: Wed Mar 15 15:40:02 2006 New Revision: 24387 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: (arre, pedronis) passing a first simple virtual container, struct to be precise, test. Not clear whether using specialised struct instead of a generic approach to layout is the best solution, worked easely enough for the simple case. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Wed Mar 15 15:40:02 2006 @@ -8,6 +8,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.rpython import rgenop from pypy.jit import hintmodel, rtimeshift +from pypy.jit import hintcontainer class HintTypeSystem(TypeSystem): name = "hinttypesystem" @@ -99,6 +100,9 @@ return hop.inputarg(hop.r_result, arg=0) def translate_op_getfield(self, hop): + if isinstance(hop.args_r[0], BlueRepr): + return hop.args_r[0].timeshift_getfield(hop) + # non virtual case ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) RESTYPE = originalconcretetype(hop.s_result) @@ -136,6 +140,14 @@ [v_jitstate, c_fielddesc, v_argbox, v_index, c_resulttype], ts.s_RedBox) + def translate_op_setfield(self, hop): + if isinstance(hop.args_r[0], BlueRepr): + return hop.args_r[0].timeshift_setfield(hop) + # non virtual case ... + + def translate_op_malloc(self, hop): + r_result = hop.r_result + return r_result.create(hop) class HintLowLevelOpList(LowLevelOpList): @@ -189,6 +201,26 @@ else: return hs_c.__class__, "red", hs_c.concretetype +class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractContainer)): + + def rtyper_makerepr((ts, hs_container), hrtyper): + assert isinstance(hs_container.contentdef, hintcontainer.VirtualStructDef) + return BlueStructRepr(hs_container.concretetype, hs_container.contentdef, + hrtyper.timeshifter) + + def rtyper_makekey((ts, hs_container), hrtyper): + assert isinstance(hs_container.contentdef, hintcontainer.VirtualStructDef) + vstructdef = hs_container.contentdef + + assert vstructdef.vparent is None + + key = [hs_container.__class__, vstructdef.T] + for name in vstructdef.names: + fielditem = vstructdef.fields[name] + key.append(fielditem) + + return tuple(key) + class __extend__(pairtype(HintTypeSystem, annmodel.SomeImpossibleValue)): def rtyper_makerepr((ts, hs_c), hrtyper): @@ -219,6 +251,91 @@ def residual_values(self, ll_value): return [ll_value] +class BlueRepr(Repr): + pass + + +class BlueStructRepr(BlueRepr): + def __init__(self, original_concretetype, virtualstructdef, timeshifter): + self.original_concretetype = original_concretetype + self.timeshifter = timeshifter + self.lowleveltype = timeshifter.r_RedBox.lowleveltype + self.CONTENT = lltype.GcForwardReference() + self.vstructdef = virtualstructdef + + def fldname(self, name): + return "fld_%s" % name + + def _setup_repr(self): + field_reprs = {} + fields = [("tag" ,rtimeshift.VCONTAINER)] + vstructdef = self.vstructdef + hrtyper = self.timeshifter.hrtyper + for name in vstructdef.names: + fieldvalue = vstructdef.fields[name] + field_repr = hrtyper.getrepr(fieldvalue.s_value) + field_reprs[name] = field_repr + fields.append((self.fldname(name), field_repr.lowleveltype)) + self.CONTENT.become(lltype.GcStruct('vstruct', *fields)) + self.field_reprs = field_reprs + + # helpers + + def create(self, hop): + llops = hop.llops + c_CONTENT = inputconst(lltype.Void, self.CONTENT) + v_content = hop.genop('malloc', [c_CONTENT], resulttype=lltype.Ptr(self.CONTENT)) + for name, field_repr in self.field_reprs.iteritems(): + if isinstance(field_repr, RedRepr): + T = field_repr.original_concretetype + c_defl = inputconst(T, T._defl()) + s_defl = annmodel.lltype_to_annotation(T) + v_field = llops.genmixlevelhelpercall(rtimeshift.ConstRedBox.ll_fromvalue, + [s_defl], [c_defl], + self.timeshifter.s_RedBox) + c_name = inputconst(lltype.Void, self.fldname(name)) + hop.genop('setfield', [v_content, c_name, v_field]) + VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) + v_content = hop.genop('cast_pointer', [v_content], + resulttype=VCONTPTR) + return llops.genmixlevelhelpercall(rtimeshift.ContainerRedBox.ll_make_container_box, + [annmodel.SomePtr(VCONTPTR)], [v_content], + self.timeshifter.s_RedBox) + + def timeshift_setfield(self, hop): + llops = hop.llops + assert hop.args_s[1].is_constant() + name = hop.args_s[1].const + field_repr = self.field_reprs[name] + v_box = hop.inputarg(self, arg=0) + v_value = hop.inputarg(field_repr, arg=2) + VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) + v_content = llops.genmixlevelhelpercall(rtimeshift.ll_getcontent, + [self.timeshifter.s_RedBox], [v_box], + annmodel.SomePtr(VCONTPTR)) + v_content = hop.genop('cast_pointer', [v_content], + resulttype=lltype.Ptr(self.CONTENT)) + c_name = inputconst(lltype.Void, self.fldname(name)) + hop.genop('setfield', [v_content, c_name, v_value]) + + + def timeshift_getfield(self, hop): + llops = hop.llops + assert hop.args_s[1].is_constant() + name = hop.args_s[1].const + field_repr = self.field_reprs[name] + v_box = hop.inputarg(self, arg=0) + VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) + v_content = llops.genmixlevelhelpercall(rtimeshift.ll_getcontent, + [self.timeshifter.s_RedBox], [v_box], + annmodel.SomePtr(VCONTPTR)) + v_content = hop.genop('cast_pointer', [v_content], + resulttype=lltype.Ptr(self.CONTENT)) + c_name = inputconst(lltype.Void, self.fldname(name)) + return hop.genop('getfield', [v_content, c_name], + resulttype=field_repr.lowleveltype) + + class GreenRepr(Repr): def __init__(self, lowleveltype): self.lowleveltype = lowleveltype Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Wed Mar 15 15:40:02 2006 @@ -41,6 +41,22 @@ def getgenvar(self): return self.genvar +VCONTAINER = lltype.GcStruct("vcontainer") + +class ContainerRedBox(RedBox): + def __init__(self, content): + self.content = content + + def getgenvar(self): # not support at the moment + raise RuntimeError("cannot force virtual containers") + + def ll_make_container_box(content): + return ContainerRedBox(content) + ll_make_container_box = staticmethod(ll_make_container_box) + +def ll_getcontent(box): + assert isinstance(box, ContainerRedBox) + return box.content class ConstRedBox(RedBox): "A red box that contains a run-time constant." Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Wed Mar 15 15:40:02 2006 @@ -284,3 +284,20 @@ insns, res = timeshift(ll_function, [a1], [0]) assert res == 42 assert insns == {} + +def test_simple_struct_malloc(): + S = lltype.GcStruct('helloworld', ('hello', lltype.Signed), + ('world', lltype.Signed)) + def ll_function(x): + s = lltype.malloc(S) + s.hello = x + return s.hello + s.world + + insns, res = timeshift(ll_function, [3], []) + assert res == 3 + assert insns == {'int_add': 1} + + insns, res = timeshift(ll_function, [3], [0]) + assert res == 3 + assert insns == {} + From bea at codespeak.net Wed Mar 15 16:59:15 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Wed, 15 Mar 2006 16:59:15 +0100 (CET) Subject: [pypy-svn] r24394 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060315155915.4CD6810086@code0.codespeak.net> Author: bea Date: Wed Mar 15 16:59:13 2006 New Revision: 24394 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: update with goals and names of people participating Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Wed Mar 15 16:59:13 2006 @@ -1,12 +1,61 @@ Post-PyCon 2006 Sprint Report ============================= -After PyCon this year, we held four days of sprints. There were lots +After PyCon this year, we held four days of sprints, 27th Feb-2 March 2006. There were lots of people new to PyPy and a couple of old friends we hadn't seen for a while. +Here are the list of people participating in the sprint: +( some for only for one day, others for the full sprint) + +Gene Oden +Bob Ippolito +Josh Gilbert +Geroge Paci +Pat Maupin +Martin Blais +Stuart Williams +Jiwon Seo +Michael Twomey +Anders Lehmann +Nik Haldimann +Samuele Pedronis +Armin Rigo +Michael Hudson +Wanja Saatkamp +Beatrice D?ring +Anders Chrigstrom +Richard Emslie +(Christian Tismer) +(Holger Krekel) + + +The announced goals for the sprint was: + +- Work on an 'rctypes' module aiming at letting us use a ctypes + implementation of an extension module from the compiled pypy-c. + + - Writing ctypes implementations of modules to be used by the above + tool. + + - Experimenting with different garbage collection strategies. + + - Implementing Python 2.5 features in PyPy + + - Implementation of constraints solvers and integration of dataflow + variables to PyPy. + + - Implement new features and improve the 'py' lib and py.test + which are heavily used by PyPy (doctests/test selection/...). + + - Generally experiment with PyPy -- for example, play with + transparent distribution of objects or coroutines and stackless + features at application level. + + + Day 1 ------ +------- Monday began with a 45 minute introduction/tutorial by Michael (which was videoed -- watch for it arriving on codespeak soon-ish) and then a From pedronis at codespeak.net Wed Mar 15 17:55:21 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Mar 2006 17:55:21 +0100 (CET) Subject: [pypy-svn] r24399 - in pypy/dist/pypy/jit: . test Message-ID: <20060315165521.E7D2E1007F@code0.codespeak.net> Author: pedronis Date: Wed Mar 15 17:55:19 2006 New Revision: 24399 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: (arre, pedronis) some support for virtual substrucures. Carry around the topmost parent and an address to the substructure. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Wed Mar 15 17:55:19 2006 @@ -5,7 +5,7 @@ from pypy.rpython.rmodel import Repr, inputconst from pypy.rpython.rstr import string_repr from pypy.rpython.typesystem import TypeSystem -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython import rgenop from pypy.jit import hintmodel, rtimeshift from pypy.jit import hintcontainer @@ -144,6 +144,13 @@ if isinstance(hop.args_r[0], BlueRepr): return hop.args_r[0].timeshift_setfield(hop) # non virtual case ... + raise NotImplementedError + + def translate_op_getsubstruct(self, hop): + if isinstance(hop.args_r[0], BlueRepr): + return hop.args_r[0].timeshift_getsubstruct(hop) + # non virtual case ... + raise NotImplementedError def translate_op_malloc(self, hop): r_result = hop.r_result @@ -212,9 +219,21 @@ assert isinstance(hs_container.contentdef, hintcontainer.VirtualStructDef) vstructdef = hs_container.contentdef - assert vstructdef.vparent is None + # compute reconstruction information up to our top-most parent + chain = [vstructdef.T] + cur = vstructdef + while cur.vparent is not None: + for name, fieldvalue in cur.vparent.fields.iteritems(): + s_field = fieldvalue.s_value + if isinstance(s_field, hintmodel.SomeLLAbstractContainer): + if s_field.contentdef is cur: + chain.append((name, cur.vparent.T)) + break + else: + assert False, "can't find ourself in parent" + cur = cur.vparent - key = [hs_container.__class__, vstructdef.T] + key = [hs_container.__class__, tuple(chain)] for name in vstructdef.names: fielditem = vstructdef.fields[name] key.append(fielditem) @@ -260,31 +279,44 @@ self.original_concretetype = original_concretetype self.timeshifter = timeshifter self.lowleveltype = timeshifter.r_RedBox.lowleveltype - self.CONTENT = lltype.GcForwardReference() + if virtualstructdef.vparent is None: + self.ENVELOPE = lltype.GcForwardReference() self.vstructdef = virtualstructdef def fldname(self, name): - return "fld_%s" % name + return name def _setup_repr(self): field_reprs = {} - fields = [("tag" ,rtimeshift.VCONTAINER)] + fields = [] vstructdef = self.vstructdef hrtyper = self.timeshifter.hrtyper + T = self.original_concretetype.TO for name in vstructdef.names: fieldvalue = vstructdef.fields[name] field_repr = hrtyper.getrepr(fieldvalue.s_value) field_reprs[name] = field_repr - fields.append((self.fldname(name), field_repr.lowleveltype)) - self.CONTENT.become(lltype.GcStruct('vstruct', *fields)) + SUBFIELD = getattr(T, name) + if isinstance(SUBFIELD, lltype.Struct): + # virtual substructure case + field_lltype = field_repr.DATA + else: + field_lltype = field_repr.lowleveltype + fields.append((self.fldname(name), field_lltype)) self.field_reprs = field_reprs + self.DATA = lltype.Struct('vstruct', *fields) + if vstructdef.vparent is None: + self.ENVELOPE.become(lltype.GcStruct('vstruct_envelope', ('tag', rtimeshift.VCONTAINER), + ('data', self.DATA))) # helpers def create(self, hop): llops = hop.llops - c_CONTENT = inputconst(lltype.Void, self.CONTENT) - v_content = hop.genop('malloc', [c_CONTENT], resulttype=lltype.Ptr(self.CONTENT)) + c_ENVELOPE = inputconst(lltype.Void, self.ENVELOPE) + v_envelope = hop.genop('malloc', [c_ENVELOPE], resulttype=lltype.Ptr(self.ENVELOPE)) + c_data = inputconst(lltype.Void, 'data') + v_data = hop.genop('getsubstruct', [v_envelope, c_data], lltype.Ptr(self.DATA)) for name, field_repr in self.field_reprs.iteritems(): if isinstance(field_repr, RedRepr): T = field_repr.original_concretetype @@ -294,13 +326,28 @@ [s_defl], [c_defl], self.timeshifter.s_RedBox) c_name = inputconst(lltype.Void, self.fldname(name)) - hop.genop('setfield', [v_content, c_name, v_field]) + hop.genop('setfield', [v_data, c_name, v_field]) VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) - v_content = hop.genop('cast_pointer', [v_content], - resulttype=VCONTPTR) + v_envelope = hop.genop('cast_pointer', [v_envelope], + resulttype=VCONTPTR) + v_content = hop.genop('cast_ptr_to_adr', [v_data], resulttype=llmemory.Address) return llops.genmixlevelhelpercall(rtimeshift.ContainerRedBox.ll_make_container_box, - [annmodel.SomePtr(VCONTPTR)], [v_content], + [annmodel.SomePtr(VCONTPTR), annmodel.SomeAddress()], + [v_envelope, v_content], self.timeshifter.s_RedBox) + + def getdata(self, hop, v_box): + llops = hop.llops + rtyper = self.timeshifter.rtyper + DATAPTR = lltype.Ptr(self.DATA) + v_data_addr = llops.genmixlevelhelpercall(rtimeshift.ll_getcontent, + [self.timeshifter.s_RedBox], + [v_box], + annmodel.SomeAddress()) + # cannot do this inside ll_getcontent because DATAPTR parts can be setup only later :( + v_data = hop.genop('cast_adr_to_ptr', [v_data_addr], resulttype=DATAPTR) + return v_data + def timeshift_setfield(self, hop): llops = hop.llops @@ -309,15 +356,9 @@ field_repr = self.field_reprs[name] v_box = hop.inputarg(self, arg=0) v_value = hop.inputarg(field_repr, arg=2) - VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) - v_content = llops.genmixlevelhelpercall(rtimeshift.ll_getcontent, - [self.timeshifter.s_RedBox], [v_box], - annmodel.SomePtr(VCONTPTR)) - v_content = hop.genop('cast_pointer', [v_content], - resulttype=lltype.Ptr(self.CONTENT)) + v_data = self.getdata(hop, v_box) c_name = inputconst(lltype.Void, self.fldname(name)) - hop.genop('setfield', [v_content, c_name, v_value]) - + hop.genop('setfield', [v_data, c_name, v_value]) def timeshift_getfield(self, hop): llops = hop.llops @@ -325,16 +366,29 @@ name = hop.args_s[1].const field_repr = self.field_reprs[name] v_box = hop.inputarg(self, arg=0) - VCONTPTR = lltype.Ptr(rtimeshift.VCONTAINER) - v_content = llops.genmixlevelhelpercall(rtimeshift.ll_getcontent, - [self.timeshifter.s_RedBox], [v_box], - annmodel.SomePtr(VCONTPTR)) - v_content = hop.genop('cast_pointer', [v_content], - resulttype=lltype.Ptr(self.CONTENT)) + v_data = self.getdata(hop, v_box) c_name = inputconst(lltype.Void, self.fldname(name)) - return hop.genop('getfield', [v_content, c_name], + return hop.genop('getfield', [v_data, c_name], resulttype=field_repr.lowleveltype) + def timeshift_getsubstruct(self, hop): + llops = hop.llops + assert hop.args_s[1].is_constant() + name = hop.args_s[1].const + field_repr = self.field_reprs[name] + v_box = hop.inputarg(self, arg=0) + v_data = self.getdata(hop, v_box) + c_name = inputconst(lltype.Void, self.fldname(name)) + NEWDATAPTR = lltype.Ptr(field_repr.DATA) + v_newdata = hop.genop('getsubstruct', [v_data, c_name], + resulttype=NEWDATAPTR) + v_content = hop.genop('cast_ptr_to_adr', [v_newdata], resulttype=llmemory.Address) + return llops.genmixlevelhelpercall(rtimeshift.ContainerRedBox.ll_make_subcontainer_box, + [self.timeshifter.s_RedBox, annmodel.SomeAddress()], + [v_box, v_content], + self.timeshifter.s_RedBox) + + class GreenRepr(Repr): def __init__(self, lowleveltype): Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Wed Mar 15 17:55:19 2006 @@ -44,19 +44,29 @@ VCONTAINER = lltype.GcStruct("vcontainer") class ContainerRedBox(RedBox): - def __init__(self, content): - self.content = content + def __init__(self, envelope, content_addr): + self.envelope = envelope + self.content_addr = content_addr def getgenvar(self): # not support at the moment raise RuntimeError("cannot force virtual containers") - def ll_make_container_box(content): - return ContainerRedBox(content) + def ll_make_container_box(envelope, content_addr): + return ContainerRedBox(envelope, content_addr) ll_make_container_box = staticmethod(ll_make_container_box) + def ll_make_subcontainer_box(box, content_addr): + return ContainerRedBox(box.envelope, content_addr) + ll_make_subcontainer_box = staticmethod(ll_make_subcontainer_box) + + +def ll_getenvelope(box): + assert isinstance(box, ContainerRedBox) + return box.envelope + def ll_getcontent(box): assert isinstance(box, ContainerRedBox) - return box.content + return box.content_addr class ConstRedBox(RedBox): "A red box that contains a run-time constant." Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Wed Mar 15 17:55:19 2006 @@ -301,3 +301,18 @@ assert res == 3 assert insns == {} +def test_inlined_substructure(): + S = lltype.Struct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) + def ll_function(k): + t = lltype.malloc(T) + t.s.n = k + l = t.s.n + return l + insns, res = timeshift(ll_function, [7], []) + assert res == 7 + assert insns == {} + + insns, res = timeshift(ll_function, [7], [0]) + assert res == 7 + assert insns == {} From auc at codespeak.net Wed Mar 15 17:56:22 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 15 Mar 2006 17:56:22 +0100 (CET) Subject: [pypy-svn] r24400 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060315165622.E71A61008F@code0.codespeak.net> Author: auc Date: Wed Mar 15 17:56:19 2006 New Revision: 24400 Removed: pypy/dist/pypy/lib/logic/computation_space/state.py Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py pypy/dist/pypy/lib/logic/computation_space/test_variable.py pypy/dist/pypy/lib/logic/computation_space/variable.py Log: big code shrink & refactoring Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 15 17:56:19 2006 @@ -4,17 +4,15 @@ # constraint propagation over finite integer domains) # and other kinds of specialized propagators -from threading import Thread, Condition, RLock, local - -from state import Succeeded, Failed, Unknown - -from variable import EqSet, CsVar, NoValue, NoDom, \ - VariableException, NotAVariable, AlreadyBound +from variable import Var, NoValue, NoDom from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor import event # NewSpace, Clone, Revise +class Succeeded: pass +class Failed(Exception): pass + class Alternative(object): def __init__(self, choices): @@ -33,50 +31,35 @@ pass #----------- Store Exceptions ---------------------------- -class UnboundVariable(VariableException): - def __str__(self): - return "%s has no value yet" % self.name - -class AlreadyBound(VariableException): - def __str__(self): - return "%s is already bound" % self.name -class NotInStore(VariableException): +class NotInStore(Exception): + def __init__(self, name): + self.name = name + def __str__(self): return "%s not in the store" % self.name -class OutOfDomain(VariableException): - def __str__(self): - return "value not in domain of %s" % self.name - class UnificationFailure(Exception): def __init__(self, var1, var2, cause=None): self.var1, self.var2 = (var1, var2) self.cause = cause def __str__(self): - diag = "%s %s can't be unified" + diag = "%s %s can't be unified" % \ + (self.var1, self.var2) if self.cause: diag += " because %s" % self.cause - return diag % (self.var1, self.var2) - -class IncompatibleDomains(Exception): - def __init__(self, var1, var2): - self.var1, self.var2 = (var1, var2) - def __str__(self): - return "%s %s have incompatible domains" % \ - (self.var1, self.var2) + return diag #---- ComputationSpace ------------------------------- class ComputationSpace(object): - # we have to enforce only one distributor - # thread running in one space at the same time + # convenience id _id_count = 0 def __init__(self, problem, parent=None): self.id = ComputationSpace._id_count ComputationSpace._id_count += 1 - self.status = Unknown + self.status = None # consistency-preserving stuff self.in_transaction = False self.distributor = DefaultDistributor(self) @@ -104,7 +87,7 @@ self.copy_domains(parent) self.copy_constraints(parent) # ... - self.status = Unknown + self.status = None self.distributor = parent.distributor.__class__(self) #-- utilities & instrumentation ----------------------------- @@ -227,7 +210,7 @@ at most one choose running in a given space at a given time ---- - this is used by the distributor thread + this is used by the distributor """ def merge(self): @@ -258,25 +241,27 @@ def var(self, name): """creates a single assignment variable of name name and puts it into the store""" - v = CsVar(name, self) - self.add_unbound(v) + #v = Var(name, self) + v = Var(name=name) + self.add_unbound(v, name) return v + def bind(self, var, val): # kill me ! + var.bind(val) + def make_vars(self, *names): variables = [] for name in names: variables.append(self.var(name)) return tuple(variables) - def add_unbound(self, var): + def add_unbound(self, var, name): """add unbound variable to the store""" if var in self.vars: - raise AlreadyInStore(var.name) - #print "adding %s to the store" % var + print "warning :", name, "is already in store" self.vars.add(var) - self.names[var.name] = var - # put into new singleton equiv. set - var.val = EqSet([var]) + self.names[name] = var + print "just created new var %s" % var def get_var_by_name(self, name): """looks up one variable""" @@ -295,7 +280,7 @@ def is_bound(self, var): """check wether a var is locally bound""" - return var.is_bound() or len(self.dom(var)) == 1 + return len(self.dom(var)) == 1 def val(self, var): """return the local binding without blocking""" @@ -307,14 +292,14 @@ def set_dom(self, var, dom): """bind variable to domain""" - assert(isinstance(var, CsVar) and (var in self.vars)) + assert(isinstance(var, Var) and (var in self.vars)) if var.is_bound(): print "warning : setting domain %s to bound var %s" \ % (dom, var) self.doms[var] = FiniteDomain(dom) def dom(self, var): - assert isinstance(var, CsVar) + assert isinstance(var, Var) return self.doms.get(var, NoDom) try: return self.doms[var] @@ -408,228 +393,3 @@ # the set of satifiable constraints if const in affected_constraints: affected_constraints.remove(const) - - def _compatible_domains(self, var, eqs): - """check that the domain of var is compatible - with the domains of the vars in the eqs - """ - if self.dom(var) == NoDom: return True - empty = set() - for v in eqs: - if self.dom(v) == NoDom: continue - if self.dom(v).intersection(self.dom(var)) == empty: - return False - return True - - #-- collect / restore utilities for domains - - def collect_domains(self, varset): - """makes a copy of domains of a set of vars - into a var -> dom mapping - """ - dom = {} - for var in varset: - if self.dom(var) != NoDom: - dom[var] = self.dom(var).copy() - return dom - - def restore_domains(self, domains): - """sets the domain of the vars in the domains mapping - to their (previous) value - """ - for var, dom in domains.items(): - self.set_dom(var, dom) - - - #-- BIND ------------------------------------------- - - def bind(self, var, val): - """1. (unbound)Variable/(unbound)Variable or - 2. (unbound)Variable/(bound)Variable or - 3. (unbound)Variable/Value binding - """ - # just introduced complete dataflow behaviour, - # where binding several times to compatible - # values is allowed provided no information is - # removed (this last condition remains to be checked) - assert(isinstance(var, CsVar) and (var in self.vars)) - if var == val: - return - if _both_are_vars(var, val): - if _both_are_bound(var, val): - if _unifiable(var, val): - return # XXX check corrrectness - raise UnificationFailure(var, val) - if var._is_bound(): # 2b. var is bound, not var - self.bind(val, var) - elif val._is_bound(): # 2a.var is bound, not val - self._bind(var.val, val.val) - else: # 1. both are unbound - self._alias(var, val) - else: # 3. val is really a value - if var._is_bound(): - if _unifiable(var.val, val): - return # XXX check correctness - raise UnificationFailure(var, val) - self._bind(var.val, val) - - def _bind(self, eqs, val): - # print "variable - value binding : %s %s" % (eqs, val) - # bind all vars in the eqset to val - for var in eqs: - if self.dom(var) != NoDom: - if val not in self.dom(var).get_values(): - # undo the half-done binding - for v in eqs: - v.val = eqs - raise OutOfDomain(var) - var.val = val - - def _alias(self, v1, v2): - for v in v1.val: - if not self._compatible_domains(v, v2.val): - raise IncompatibleDomains(v1, v2) - self._really_alias(v1.val, v2.val) - - def _really_alias(self, eqs1, eqs2): - # print "unbound variables binding : %s %s" % (eqs1, eqs2) - if eqs1 == eqs2: return - # merge two equisets into one - eqs1 |= eqs2 - # let's reassign everybody to the merged eq - for var in eqs1: - var.val = eqs1 - - #-- UNIFY ------------------------------------------ - - def unify(self, x, y): - self.in_transaction = True - try: - try: - self._really_unify(x, y) - for var in self.vars: - if var._changed: - var._commit() - except Exception, cause: - for var in self.vars: - if var._changed: - var._abort() - if isinstance(cause, UnificationFailure): - raise - raise UnificationFailure(x, y, cause) - finally: - self.in_transaction = False - - def _really_unify(self, x, y): - # print "unify %s with %s" % (x,y) - if not _unifiable(x, y): raise UnificationFailure(x, y) - if not x in self.vars: - if not y in self.vars: - # duh ! x & y not vars - if x != y: raise UnificationFailure(x, y) - else: return - # same call, reverse args. order - self._unify_var_val(y, x) - elif not y in self.vars: - # x is Var, y a value - self._unify_var_val(x, y) - elif _both_are_bound(x, y): - self._unify_bound(x,y) - elif x._is_bound(): - self.bind(x,y) - else: - self.bind(y,x) - - def _unify_var_val(self, x, y): - if x.val != y: # what else ? - self.bind(x, y) - - def _unify_bound(self, x, y): - # print "unify bound %s %s" % (x, y) - vx, vy = (x.val, y.val) - if type(vx) in [list, set] and isinstance(vy, type(vx)): - self._unify_iterable(x, y) - elif type(vx) is dict and isinstance(vy, type(vx)): - self._unify_mapping(x, y) - else: - if vx != vy: - raise UnificationFailure(x, y) - - def _unify_iterable(self, x, y): - #print "unify sequences %s %s" % (x, y) - vx, vy = (x.val, y.val) - idx, top = (0, len(vx)) - while (idx < top): - self._really_unify(vx[idx], vy[idx]) - idx += 1 - - def _unify_mapping(self, x, y): - # print "unify mappings %s %s" % (x, y) - vx, vy = (x.val, y.val) - for xk in vx.keys(): - self._really_unify(vx[xk], vy[xk]) - -#-- Unifiability checks--------------------------------------- -#-- -#-- quite costly & could be merged back in unify - -def _iterable(thing): - return type(thing) in [tuple, frozenset] - -def _mapping(thing): - # should be frozendict (python 2.5 ?) - return isinstance(thing, dict) - -# memoizer for _unifiable -_unifiable_memo = set() - -def _unifiable(term1, term2): - global _unifiable_memo - _unifiable_memo = set() - return _really_unifiable(term1, term2) - -def _really_unifiable(term1, term2): - """Checks wether two terms can be unified""" - if ((id(term1), id(term2))) in _unifiable_memo: return False - _unifiable_memo.add((id(term1), id(term2))) - # print "unifiable ? %s %s" % (term1, term2) - if _iterable(term1): - if _iterable(term2): - return _iterable_unifiable(term1, term2) - return False - if _mapping(term1) and _mapping(term2): - return _mapping_unifiable(term1, term2) - if not(isinstance(term1, CsVar) or isinstance(term2, CsVar)): - return term1 == term2 # same 'atomic' object - return True - -def _iterable_unifiable(c1, c2): - """Checks wether two iterables can be unified""" - # print "unifiable sequences ? %s %s" % (c1, c2) - if len(c1) != len(c2): return False - idx, top = (0, len(c1)) - while(idx < top): - if not _really_unifiable(c1[idx], c2[idx]): - return False - idx += 1 - return True - -def _mapping_unifiable(m1, m2): - """Checks wether two mappings can be unified""" - # print "unifiable mappings ? %s %s" % (m1, m2) - if len(m1) != len(m2): return False - if m1.keys() != m2.keys(): return False - v1, v2 = (m1.items(), m2.items()) - v1.sort() - v2.sort() - return _iterable_unifiable([e[1] for e in v1], - [e[1] for e in v2]) - -#-- Some utilities ------------------------------------------- - -def _both_are_vars(v1, v2): - return isinstance(v1, CsVar) and isinstance(v2, CsVar) - -def _both_are_bound(v1, v2): - return v1._is_bound() and v2._is_bound() - Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 15 17:56:19 2006 @@ -36,264 +36,6 @@ assert x == sp.get_var_by_name('x') raises(space.NotInStore, sp.get_var_by_name, 'y') - def test_already_bound(self): - sp = newspace() - x = sp.var('x') - sp.bind(x, 42) - sp.bind(x, 42) - raises(space.UnificationFailure, sp.bind, x, 43) - - def test_bind_var_var(self): - sp = newspace() - x, y, z = sp.var('x'), sp.var('y'), sp.var('z') - sp.bind(x, z) - assert x.val == space.EqSet([x, z]) - assert y.val == space.EqSet([y]) - assert z.val == space.EqSet([x, z]) - z.bind(42) - assert z.val == 42 - assert x.val == 42 - y.bind(42) - assert y.val == 42 - y.bind(z) - - def test_bind_var_val(self): - sp = newspace() - x, y, z = sp.var('x'), sp.var('y'), sp.var('z') - sp.bind(x, z) - sp.bind(y, 42) - sp.bind(z, 3.14) - assert x.val == 3.14 - assert y.val == 42 - assert z.val == 3.14 - - def test_unify_same(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.bind(x, [42, z]) - sp.bind(y, [z, 42]) - sp.bind(w, [z, 43]) - raises(space.UnificationFailure, sp.unify, x, w) - sp.unify(x, y) - assert z.val == 42 - - def test_double_unification(self): - sp = newspace() - x, y, z = (sp.var('x'), sp.var('y'), - sp.var('z')) - sp.bind(x, 42) - sp.bind(y, z) - sp.unify(x, y) - assert z.val == 42 - sp.unify(x, y) - assert (z.val == x.val) and (x.val == y.val) - - - def test_unify_values(self): - sp = newspace() - x, y = sp.var('x'), sp.var('y') - sp.bind(x, [1, 2, 3]) - sp.bind(y, [1, 2, 3]) - sp.unify(x, y) - assert x.val == [1, 2, 3] - assert y.val == [1, 2, 3] - - def test_unify_lists_success(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.bind(x, [42, z]) - sp.bind(y, [w, 44]) - sp.unify(x, y) - assert x.val == [42, z] - assert y.val == [w, 44] - assert z.val == 44 - assert w.val == 42 - - def test_unify_dicts_success(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.bind(x, {1:42, 2:z}) - sp.bind(y, {1:w, 2:44}) - sp.unify(x, y) - assert x.val == {1:42, 2:z} - assert y.val == {1:w, 2:44} - assert z.val == 44 - assert w.val == 42 - - def test_unify_failure(self): - sp = newspace() - x,y,z = sp.var('x'), sp.var('y'), sp.var('z') - sp.bind(x, [42, z]) - sp.bind(y, [z, 44]) - raises(space.UnificationFailure, sp.unify, x, y) - # check store consistency - assert x.val == [42, z] - assert y.val == [z, 44] - assert z.val == space.EqSet([z]) - - def test_unify_failure2(self): - sp = newspace() - x,y,z,w = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w')) - sp.bind(x, [42, z]) - sp.bind(y, [w, 44]) - sp.bind(z, w) - assert sp.in_transaction == False - raises(space.UnificationFailure, sp.unify, x, y) - assert sp.in_transaction == False - # check store consistency - assert x.val == [42, z] - assert y.val == [w, 44] - assert z.val == space.EqSet([z,w]) - assert w.val == space.EqSet([z,w]) - - def test_unify_circular(self): - sp = newspace() - x, y, z, w, a, b = (sp.var('x'), sp.var('y'), - sp.var('z'), sp.var('w'), - sp.var('a'), sp.var('b')) - sp.bind(x, [y]) - sp.bind(y, [x]) - raises(space.UnificationFailure, sp.unify, x, y) - sp.bind(z, [1, w]) - sp.bind(w, [z, 2]) - raises(space.UnificationFailure, sp.unify, z, w) - sp.bind(a, {1:42, 2:b}) - sp.bind(b, {1:a, 2:42}) - raises(space.UnificationFailure, sp.unify, a, b) - # check store consistency - assert x.val == [y] - assert y.val == [x] - assert z.val == [1, w] - assert w.val == [z, 2] - assert a.val == {1:42, 2:b} - assert b.val == {1:a, 2:42} - - - def test_threads_creating_vars(self): - sp = newspace() - def create_var(thread, *args): - x = sp.var('x') - - def create_var2(thread, *args): - raises(v.AlreadyInStore, sp.var, 'x') - - t1, t2 = (FunThread(create_var), - FunThread(create_var2)) - t1.start() - t2.start() - t1.join() - t2.join() - - - def test_threads_binding_vars(self): - sp = newspace() - - def do_stuff(thread, var, val): - thread.raised = False - try: - # pb. with TLS (thread-local-stuff) in - # cs class - sp.bind(var, val) - except Exception, e: - print e - thread.raised = True - assert isinstance(e, space.UnificationFailure) - - x = sp.var('x') - vars_ = [] - for nvar in range(100): - v = sp.var('x-'+str(nvar)) - sp.bind(x, v) - vars_.append(v) - - for var in vars_: - assert var in sp.vars - assert var.val == x.val - - t1, t2 = (FunThread(do_stuff, x, 42), - FunThread(do_stuff, x, 43)) - t1.start() - t2.start() - t1.join() - t2.join() - #check that every var is really bound to 42 or 43 - for var in vars_: - assert var in sp.vars - assert var.val == x.val - assert (t2.raised and not t1.raised) or \ - (t1.raised and not t2.raised) - - - def test_threads_waiting_for_unbound_var(self): - sp = newspace() - import time - - def near(v1, v2, err): - return abs(v1 - v2) < err - - start_time = time.time() - - def wait_on_unbound(thread, var, start_time): - thread.val = var.wait() - thread.waited = time.time() - start_time - - x = sp.var('x') - t1, t2 = (FunThread(wait_on_unbound, x, start_time), - FunThread(wait_on_unbound, x, start_time)) - t1.start() - t2.start() - time.sleep(1) - sp.bind(x, 42) - t1.join() - t2.join() - assert t1.val == 42 - assert t2.val == 42 - assert near(t1.waited, 1, .1) - assert near(t2.waited, 1, .1) - - - def test_set_var_domain(self): - sp = newspace() - x = sp.var('x') - sp.set_dom(x, [1, 3, 5]) - assert sp.dom(x) == c.FiniteDomain([1, 3, 5]) - - def test_bind_with_domain(self): - sp = newspace() - x = sp.var('x') - sp.set_dom(x, [1, 2, 3]) - raises(space.OutOfDomain, sp.bind, x, 42) - sp.bind(x, 3) - assert x.val == 3 - - def test_bind_with_incompatible_domains(self): - sp = newspace() - x, y = sp.var('x'), sp.var('y') - sp.set_dom(x, [1, 2]) - sp.set_dom(y, [3, 4]) - raises(space.IncompatibleDomains, sp.bind, x, y) - sp.set_dom(y, [2, 4]) - sp.bind(x, y) - # check x and y are in the same equiv. set - assert x.val == y.val - - - def test_unify_with_domains(self): - sp = newspace() - x,y,z = sp.var('x'), sp.var('y'), sp.var('z') - sp.bind(x, [42, z]) - sp.bind(y, [z, 42]) - sp.set_dom(z, [1, 2, 3]) - raises(space.UnificationFailure, sp.unify, x, y) - sp.set_dom(z, [41, 42, 43]) - sp.unify(x, y) - assert z.val == 42 - assert sp.dom(z) == c.FiniteDomain([41, 42, 43]) - def test_add_expression(self): sp = newspace() x,y,z = sp.var('x'), sp.var('y'), sp.var('z') Modified: pypy/dist/pypy/lib/logic/computation_space/test_variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_variable.py Wed Mar 15 17:56:19 2006 @@ -3,7 +3,8 @@ from py.test import raises -from variable import var, NoValue, AlreadyBound, stream_repr +from variable import var, NoValue, AlreadyBound, \ + UnificationFailure, stream_repr, Eqset, unify #-- utilities --------------------- @@ -37,13 +38,199 @@ class TestSimpleVariable: - def test_basics(self): + def test_rebinding(self): x = var() assert x.val == NoValue x.bind(42) assert x.val == 42 x.bind(42) - raises(AlreadyBound, x.bind, 43) + raises(UnificationFailure, x.bind, 43) + + def test_reunifying(self): + x = var() + unify(x, 42) + unify(x, 42) + raises(UnificationFailure, x.bind, 43) + raises(UnificationFailure, unify, x, 43) + + + def test_bind_var_val(self): + x, y, z = var(), var(), var() + x.bind(z) + assert x.aliases() == z.aliases() == Eqset([x, z]) + y.bind(42) + z.bind(3.14) + assert x.val == 3.14 + assert y.val == 42 + assert z.val == 3.14 + + def test_bind_var_var(self): + x, y, z = var(), var(), var() + x.bind(z) + assert x.aliases() == Eqset([x, z]) + assert y.aliases() == Eqset([y]) + assert z.aliases() == Eqset([x, z]) + assert x.val == y.val == z.val == NoValue + z.bind(42) + assert z.val == 42 + assert x.val == 42 + y.bind(42) + assert y.val == 42 + y.bind(z) + + def test_unify_same(self): + x,y,z,w = var(), var(), var(), var() + x.bind([42, z]) + y.bind([z, 42]) + w.bind([z, 43]) + raises(UnificationFailure, unify, x, w) + unify(x, y) + assert z.val == 42 + + def test_double_unification(self): + x, y, z = var(), var(), var() + x.bind(42) + y.bind(z) + unify(x, y) + assert z.val == 42 + unify(x, y) + assert (z.val == x.val == y.val) + + def test_unify_values(self): + x, y = var(), var() + x.bind([1, 2, 3]) + y.bind([1, 2, 3]) + unify(x, y) + assert x.val == [1, 2, 3] + assert y.val == [1, 2, 3] + + def test_unify_lists_success(self): + x,y,z,w = var(), var(), var(), var() + x.bind([42, z]) + y.bind([w, 44]) + unify(x, y) + assert x.val == [42, z] + assert y.val == [w, 44] + assert z.val == 44 + assert w.val == 42 + + def test_unify_dicts_success(self): + x,y,z,w = var(), var(), var(), var() + x.bind({1:42, 2:z}) + y.bind({1:w, 2:44}) + unify(x, y) + assert x.val == {1:42, 2:z} + assert y.val == {1:w, 2:44} + assert z.val == 44 + assert w.val == 42 + + def test_unify_failure(self): + x, y, z = var(), var(), var() + x.bind([42, z]) + y.bind([z, 44]) + raises(UnificationFailure, unify, x, y) + # check state + assert x.val == [42, z] + assert y.val == [z, 44] + assert z.aliases() == Eqset([z]) + + def test_unify_failure2(self): + x,y,z,w = var(), var(), var(), var() + x.bind([42, z]) + y.bind([w, 44]) + z.bind(w) + raises(UnificationFailure, unify, x, y) + # check state + assert x.val == [42, z] + assert y.val == [w, 44] + # note that z has been bound to 42 ! + assert z.val == 42 + assert w.val == 42 + + def test_unify_circular(self): + x, y, z, w, a, b = (var(), var(), var(), + var(), var(), var()) + x.bind([y]) + y.bind([x]) + raises(UnificationFailure, unify, x, y) + z.bind([1, w]) + w.bind([z, 2]) + raises(UnificationFailure, unify, z, w) + a.bind({1:42, 2:b}) + b.bind({1:a, 2:42}) + raises(UnificationFailure, unify, a, b) + # check store consistency + assert x.val == [y] + assert y.val == [x] + assert z.val == [1, w] + assert w.val == [z, 2] + assert a.val == {1:42, 2:b} + assert b.val == {1:a, 2:42} + + + def notest_threads_binding_vars(self): + # WTF ? + #E x = var() + #> UnboundLocalError: local variable 'var' referenced before assignment + x = var() # + vars_ = [] + + def do_stuff(thread, var, val): + thread.raised = False + try: + var.bind(val) + except Exception, e: + print e + thread.raised = True + assert isinstance(e, UnificationFailure) + + for nvar in range(100): + v = var() + x.bind(v) + vars_.append(v) + + for var in vars_: + assert var.val == x.val + + t1, t2 = (FunThread(do_stuff, x, 42), + FunThread(do_stuff, x, 43)) + t1.start() + t2.start() + t1.join() + t2.join() + #check that every var is really bound to 42 or 43 + for var in vars_: + assert var in sp.vars + assert var.val == x.val + assert (t2.raised and not t1.raised) or \ + (t1.raised and not t2.raised) + + + def test_threads_waiting_for_unbound_var(self): + import time + + def near(v1, v2, err): + return abs(v1 - v2) < err + + start_time = time.time() + + def wait_on_unbound(thread, var, start_time): + thread.val = var.wait() + thread.waited = time.time() - start_time + + x = var() + t1, t2 = (FunThread(wait_on_unbound, x, start_time), + FunThread(wait_on_unbound, x, start_time)) + t1.start() + t2.start() + time.sleep(1) + x.bind(42) + t1.join() + t2.join() + assert t1.val == 42 + assert t2.val == 42 + assert near(t1.waited, 1, .1) + assert near(t2.waited, 1, .1) def test_repr_stream(self): var._vcount = 0 #ensure consistent numbering @@ -92,12 +279,12 @@ {DGenerate N+1 Xr} end end""" - print "generator in %s waits on Xs" % thread.getName() + print "generator waits on %s " % Xs X_Xr = Xs.wait() # destructure Xs if X_Xr == None: return - print "generator X_Xr", X_Xr + print "generator got X_Xr = ", X_Xr X = X_Xr[0] # ... into X - print "generator in %s binds X to %s" % (thread.getName(), n) + print "generator binds %s to %s" % (X, n) X.bind(n) # bind X to n Xr = X_Xr[1] # ... and Xr dgenerate(thread, n+1, Xr) @@ -116,12 +303,11 @@ X = var() Xr = var() Xs.bind((X, Xr)) - print "client binds Xs to X|Xr ", stream_repr(Xs) + print "client binds %s, waits on %s" % (Xs, X) x = X.wait() # wait on the value of X - print "client got", x dsum(thread, Xr, a+x, limit-1) else: - print "CLIENT binds Xs to None and exits" + print "client binds Xs to None and exits" Xs.bind(None) thread.result = a @@ -228,10 +414,10 @@ else Xr in Xs=_|Xr {Startup N-1 Xr} end end """ - if n==0: return Xs # will be End + if n==0: return Xs Xr = var() Xs.bind((var(), Xr)) - print "startup n = ", n, stream_repr(Xs) + print "startup n = ", n, Xs return startup(n-1, Xr) def ask_loop(Ys, Xs, End): @@ -250,16 +436,15 @@ X, Xr = Xs.wait() Y.bind(X.wait()) End2 = var() + print "Ask_loop Ys Xs End", Ys, Xs, End End.bind((var(), End2)) ask_loop(Yr, Xr, End2) else: End.bind(None) - print "buffer initial Ys, Xs ", stream_repr(Ys, Xs) - End = var() - End.bind(startup(n, Xs)) - print "buffer starts", stream_repr(Xs, End) - ask_loop(Ys, Xs, End.val) + End = startup(n, Xs) + print "buffer starts", Ys, Xs, End + ask_loop(Ys, Xs, End) Xs = var() Ys = var() Modified: pypy/dist/pypy/lib/logic/computation_space/variable.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/variable.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/variable.py Wed Mar 15 17:56:19 2006 @@ -2,13 +2,8 @@ import time #----------- Exceptions --------------------------------- -class VariableException(Exception): - def __init__(self, name): - self.name = name - class AlreadyBound(Exception): def __init__(self, var, val): - print "can't bind %s to %s" % (var, val) self.var = var self.val = val @@ -16,30 +11,44 @@ var, val = self.var, self.val return "can't bind %s to %s" % (var, val) -class NotAVariable(VariableException): +class UnificationFailure(Exception): + def __init__(self, var1, var2, cause=None): + self.var1, self.var2 = (var1, var2) + self.cause = cause + def __str__(self): - return "%s is not a variable" % self.name + diag = "%s %s can't be unified" % \ + (self.var1, self.var2) + if self.cause: + diag += " because %s" % self.cause + return diag #----------- Variables ---------------------------------- -class EqSet(set): pass +class Eqset(set): pass -class NoValue: pass +class NoValue: pass # kill me ! -class NoDom: pass +class NoDom: pass # kill me ! class Var(object): """Spaceless dataflow variable""" _count_lock = threading.Lock() _vcount = 0 - def __init__(self, value=NoValue): + def __init__(self, value=None, name=None): try: Var._count_lock.acquire() - self.name = str(Var._vcount) + if name: self.name = name + else: self.name = str(Var._vcount) finally: Var._count_lock.release() Var._vcount += 1 - self._val = value + if value: + self._val = value + self._bound = True + else: + self._val = Eqset([self]) + self._bound = False # a condition variable for Wait self._value_condition = threading.Condition() # for WaitNeeded @@ -47,18 +56,20 @@ # value accessors def _set_val(self, val): - if self._val != NoValue: + if self._bound: if val != self._val: raise AlreadyBound(self, val) self._val = val + self._bound = True def _get_val(self): - return self._val - val = property(_get_val, _set_val) + if self._bound: + return self._val + return NoValue def __str__(self): if self.is_bound(): - return "<%s>" % str(self._val) + return "<%s=%s>" % (self.name, self.val) return "" % self.name def __repr__(self): @@ -66,16 +77,23 @@ # public interface + val = property(_get_val, _set_val) + def is_bound(self): - return self.val != NoValue + return self._bound def is_free(self): - return not self.isbound() + return not self._bound + + def aliases(self): + if self._bound: + return Eqset([self]) + return self._val def bind(self, val): self._value_condition.acquire() try: - self.val = val + self._bind(val) self._value_condition.notifyAll() finally: self._value_condition.release() @@ -93,7 +111,7 @@ self._value_condition.wait(10) t2 = time.time() if t2-t1>10: - raise RuntimeError("possible deadlock??") + raise RuntimeError("possible deadlock on %s" % self) return self.val finally: self._value_condition.release() @@ -105,9 +123,121 @@ finally: self._need_condition.release() + + #-- the real bind -------------------------------------- + + def _bind(self, thing): + """1. aliasing of unbound variables + 2. assign unbound var to bound var + 3. assign value to self + """ + if isinstance(thing, Var): + if _both_are_bound(self, thing): + if thing.val == self.val: + return + raise UnificationFailure(self, thing) + if self.is_bound(): # 2b. self is bound, not var + var._assign(self.val) + elif thing.is_bound(): # 2a.var is bound, not self + self._assign(thing.val) + else: # 1. both are unbound + self._alias(thing) + else: # 3. thing is really a value + if self.is_bound(): + if self.val == thing: + return + raise UnificationFailure(self, thing) + self._assign(thing) + + def _assign(self, val): + # bind all aliased vars to val + # print "assignation : %s <- %s" % (self, val) + for var in self._val: + var.val = val + + def _alias(self, var): + #print "aliasing variables : %s %s" % (self, var) + eqs = var._val + if self._val == eqs: return + # merge two eqsets into one + neqs = self._val | eqs + # let's realias everyone + for var in neqs: + var._val = neqs + var = Var -#-- utility --------- +#-- UNIFY ------------------------------------------ + +def unify(x, y): + #print "unify %s with %s" % (x,y) + check_and_memoize_pair(x, y) + if not isinstance(x, Var): + if not isinstance(y, Var): + # duh ! x & y not vars + _unify_values(x, y) + # x not a var, reverse args. order + unify(y, x) + elif not isinstance(y, Var): + # x is Var, y a value + x.bind(y) + # x and y are vars + elif _both_are_bound(x, y): + _unify_values(x.val ,y.val) + elif x.is_bound(): + y.bind(x.val) + # aliasing x & y + else: + x.bind(y) + reset_memo() + +def _unify_values(x, y): + #print "unify values %s %s" % (x, y) + if type(x) in [list, set] and isinstance(y, type(x)): + _unify_iterable(x, y) + elif type(x) is dict and isinstance(y, type(x)): + _unify_mapping(x, y) + else: + if x != y: + raise UnificationFailure(x, y) + +def _unify_iterable(x, y): + #print "unify sequences %s %s" % (x, y) + idx, top = (-1, len(x)-1) + while (idx < top): + idx += 1 + xi, yi = x[idx], y[idx] + if xi == yi: continue + unify(xi, yi) + +def _unify_mapping(x, y): + #print "unify mappings %s %s" % (x, y) + for xk in x.keys(): + xi, yi = x[xk], y[xk] + if xi == yi: continue + unify(xi, yi) + +#-- memoizer for unify ----------------- + +_unification_memo = set() + +def reset_memo(): + global _unification_memo + _unification_memo.clear() + +def check_and_memoize_pair(x, y): + global _unification_memo + elt = (id(x), id(y)) + if elt in _unification_memo: + raise UnificationFailure(x, y) + _unification_memo.add(elt) + + +def _both_are_bound(v1, v2): + return v1.is_bound() and v2.is_bound() + + +#-- stream utility --------- def stream_repr(*args): """represent streams of variables whose @@ -130,63 +260,3 @@ repr_.append(' ') repr_.pop() return ''.join(repr_) - -#-- to be killed soon ---- - -class CsVar(Var): - """Dataflow variable linked to a space""" - - def __init__(self, name, cs): - Var.__init__(self) - if name in cs.names: - raise AlreadyInStore(name) - self.name = name - # the creation-time (top-level) space - self._cs = cs - # top-level 'commited' binding - self._val = NoValue - # when updated while unification happens, keep track - # of our initial value (for failure cases) - self._previous = None - self._changed = False - # a condition variable for concurrent access - self._value_condition = threading.Condition() - - # for consumption by the global cs - - def _is_bound(self): - return not isinstance(self._val, EqSet) \ - and self._val != NoValue - - # atomic unification support - - def _commit(self): - self._changed = False - - def _abort(self): - self.val = self._previous - self._changed = False - - # value accessors - def _set_val(self, val): - self._value_condition.acquire() - try: - if self._cs.in_transaction: - if not self._changed: - self._previous = self._val - self._changed = True - self._val = val - self._value_condition.notifyAll() - finally: - self._value_condition.release() - - def _get_val(self): - return self._val - val = property(_get_val, _set_val) - - def bind(self, val): - """home space bind""" - self._cs.bind(self, val) - - is_bound = _is_bound - From auc at codespeak.net Wed Mar 15 19:34:27 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 15 Mar 2006 19:34:27 +0100 (CET) Subject: [pypy-svn] r24404 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060315183427.39A611007D@code0.codespeak.net> Author: auc Date: Wed Mar 15 19:34:24 2006 New Revision: 24404 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/strategies.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: don't run the sudoku test ... Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 15 19:34:24 2006 @@ -231,8 +231,8 @@ def inject(self, restricting_problem): """add additional entities into a space""" restricting_problem(self) + self._notify(event.Clone) self._propagate() - #-- Constraint Store --------------------------------------- Modified: pypy/dist/pypy/lib/logic/computation_space/strategies.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/strategies.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/strategies.py Wed Mar 15 19:34:24 2006 @@ -32,9 +32,7 @@ if solved_space == None: return None return solved_space.merge() - - -#-- solve_all, switchable direction +#-- solve_all, switchable direction (takes problem) class Depth: pass class Breadth: pass @@ -70,7 +68,7 @@ return [sp.merge() for sp in solutions] -#-- pythonic lazy solve_all +#-- pythonic lazy solve_all (takes space) def lazily_solve_all(space, direction=Depth): Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 15 19:34:24 2006 @@ -179,25 +179,26 @@ assert sp.test_solution(sol) - def no_test_sudoku(self): - #spc = newspace(problems.sudoku) - #print spc.constraints + def test_sudoku(self): + spc = newspace(problems.sudoku) + print spc.constraints + def more_constraints(space): - f = 'puzzle1.su' + fname = 'puzzle1.su' - file = open(f) + f = open(fname) c = [] row = 1 - for line in file.readlines(): + for line in f.readlines(): for col in range(1,10): if line[col-1] != ' ': tup = ('v%d%d' % (col, row), int(line[col-1])) space.add_constraint([space.get_var_by_name(tup[0])],'%s == %d' % tup) row += 1 - #nspc = spc.clone() - #nspc.inject(more_constraints) - #print nspc.constraints - sol2 = strategies.dfs_one(strategies.sudoku) - print "done dfs" - #sol2 = [var.val for var in sol] + spc.inject(more_constraints) + print spc.constraints + sol_iter = strategies.lazily_solve_all(spc) + sol = sol_iter.next() + print sol + assert spc.test_solution(sol) From pedronis at codespeak.net Wed Mar 15 20:18:56 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Mar 2006 20:18:56 +0100 (CET) Subject: [pypy-svn] r24405 - pypy/dist/pypy/jit Message-ID: <20060315191856.D0B311007F@code0.codespeak.net> Author: pedronis Date: Wed Mar 15 20:18:55 2006 New Revision: 24405 Modified: pypy/dist/pypy/jit/hintrtyper.py Log: comment about runtime representation of virtual structure. maybe things can be simplified, the issue is gc tracking of pointers to non-gc struct vs. differences introduced through the timeshifting process. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Wed Mar 15 20:18:55 2006 @@ -278,7 +278,13 @@ def __init__(self, original_concretetype, virtualstructdef, timeshifter): self.original_concretetype = original_concretetype self.timeshifter = timeshifter - self.lowleveltype = timeshifter.r_RedBox.lowleveltype + # xxx + # this could avoid using a wrapper box completely + # which means that if the field are green we could back the original situation + # but is unclear whether there are issues with gc tracking for non-gc struct pointer, + # likely things are preserved but the timeshifted graph may introduce sufficient + # differences to make that a problem + self.lowleveltype = timeshifter.r_RedBox.lowleveltype if virtualstructdef.vparent is None: self.ENVELOPE = lltype.GcForwardReference() self.vstructdef = virtualstructdef From cfbolz at codespeak.net Wed Mar 15 20:28:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 15 Mar 2006 20:28:03 +0100 (CET) Subject: [pypy-svn] r24406 - pypy/dist/pypy/doc/weekly Message-ID: <20060315192803.692321007F@code0.codespeak.net> Author: cfbolz Date: Wed Mar 15 20:27:52 2006 New Revision: 24406 Added: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: (mwh, cfbolz): start this week in pypy with a section about gc work Added: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Wed Mar 15 20:27:52 2006 @@ -0,0 +1,42 @@ +======================= + This Week in PyPy X +======================= + +Introduction +============ + +PyCon +===== + +The Logic Sprint +================ + +Garbage Collection +================== + +This week Michael with the help of Carl, Samuele and Armin managed for +the first time to compile the pypy interpreter together with our own +garbage collector written in Python. XXX performance numbers go here. + +This required quite a bit of work and first we refactored the way the +existing two garbage collectors (reference counting and using the Boehm +collector) are implemented in the C backend. Before they were +implemented by inserting C code into appropriate places in the generated +code using string formatting. This had several disadvantages: +%-formatting C code is obviously not helpful for other backends, and it +makes writing code that reasons about the GC operations really very +hard. We rewrote this to use a "GCTransformer" to instead insert new +operations into the graphs that have equivalent functionality. + +We wrote two transfomers that re-implemented the reference counting and +Boehm policies, and a new "FrameworkGCTransformer" that inserts calls to +functions defined by one of the garbage collectors written by Carl for +his Summer of Code project. The final piece of the puzzle was a +solution to the perennial "finding roots" problem, where we went for the +exceedingly ugly and inefficient approach of keeping our own stack of +root pointers. + +And then we banged our heads against the usual obscure bugs and finally +made it work. It turns out that writing Python code that manipulates +memory addresses directly combines most of the disadvantages of C with +none of the advantages of Python... From pedronis at codespeak.net Wed Mar 15 20:41:49 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Mar 2006 20:41:49 +0100 (CET) Subject: [pypy-svn] r24407 - pypy/dist/pypy/jit Message-ID: <20060315194149.9F2E21007F@code0.codespeak.net> Author: pedronis Date: Wed Mar 15 20:41:48 2006 New Revision: 24407 Modified: pypy/dist/pypy/jit/hintrtyper.py Log: fix typos in last check-in. Brief comment about possible approach for merging. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Wed Mar 15 20:41:48 2006 @@ -274,14 +274,18 @@ pass +# merging can probably be implemented as: flatten incoming state as list of redboxes -> merge -> reconstruct +# this can reuse the current merge logic and the flattening/reconstructing can be done externally driven +# by the known types and annotations + class BlueStructRepr(BlueRepr): def __init__(self, original_concretetype, virtualstructdef, timeshifter): self.original_concretetype = original_concretetype self.timeshifter = timeshifter # xxx # this could avoid using a wrapper box completely - # which means that if the field are green we could back the original situation - # but is unclear whether there are issues with gc tracking for non-gc struct pointer, + # which means that if the fields are all green we could get back the original situation + # but is unclear whether there are issues with gc tracking for non-gc struct pointers, # likely things are preserved but the timeshifted graph may introduce sufficient # differences to make that a problem self.lowleveltype = timeshifter.r_RedBox.lowleveltype From mwh at codespeak.net Wed Mar 15 20:48:02 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 15 Mar 2006 20:48:02 +0100 (CET) Subject: [pypy-svn] r24408 - pypy/dist/pypy/doc/weekly Message-ID: <20060315194802.BFB831007F@code0.codespeak.net> Author: mwh Date: Wed Mar 15 20:47:59 2006 New Revision: 24408 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: an introduction, a short pycon section and a toning down of the "python is worse than C" comment. Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Wed Mar 15 20:47:59 2006 @@ -5,9 +5,26 @@ Introduction ============ +If a week can be a long time in politics, it can be even longer in +open source documentation... it seems that writing one summary a week +isn't really sustainable, so we're going to try to scale back to an +activity report every two weeks or so. This report covers roughly the +last month of development. + PyCon ===== +The end of February was naturally dominated by PyCon in Texas which +was attended by several core developers. We gave three well-received +talks, talked to a great many interested people and held a successful +sprint, giving several newcomers their first taste of hacking on PyPy. + +You can read more about this in the `conference report`_ and `sprint +report`_. + +.. _`conference report`: http://write.me/ +.. _`sprint report`: http://write.me/ + The Logic Sprint ================ @@ -36,7 +53,8 @@ exceedingly ugly and inefficient approach of keeping our own stack of root pointers. -And then we banged our heads against the usual obscure bugs and finally -made it work. It turns out that writing Python code that manipulates -memory addresses directly combines most of the disadvantages of C with -none of the advantages of Python... +And then we banged our heads against the usual obscure bugs and +finally made it work. It turns out that debugging C that's generated +Python code that manipulates memory addresses directly is hard on the +brain... we need to get back to being able to run everything on the +memory simulator. From pedronis at codespeak.net Wed Mar 15 23:33:41 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Mar 2006 23:33:41 +0100 (CET) Subject: [pypy-svn] r24410 - pypy/dist/pypy/jit Message-ID: <20060315223341.CA2CA1007D@code0.codespeak.net> Author: pedronis Date: Wed Mar 15 23:33:35 2006 New Revision: 24410 Modified: pypy/dist/pypy/jit/hintcontainer.py Log: xxx about virtual structure union and vparent Modified: pypy/dist/pypy/jit/hintcontainer.py ============================================================================== --- pypy/dist/pypy/jit/hintcontainer.py (original) +++ pypy/dist/pypy/jit/hintcontainer.py Wed Mar 15 23:33:35 2006 @@ -99,6 +99,7 @@ return self.fields == other.fields def union(self, other): + # xxx about vparent? assert self.T == other.T for name in self.names: self.fields[name].merge(other.fields[name]) From cfbolz at codespeak.net Thu Mar 16 01:36:56 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 01:36:56 +0100 (CET) Subject: [pypy-svn] r24415 - pypy/extradoc/sprintinfo/louvain-la-neuve-2006 Message-ID: <20060316003656.CFE8D10082@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 01:36:53 2006 New Revision: 24415 Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Log: fix rest Modified: pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt ============================================================================== --- pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt (original) +++ pypy/extradoc/sprintinfo/louvain-la-neuve-2006/pypy-oz-agenda.txt Thu Mar 16 01:36:53 2006 @@ -76,158 +76,157 @@ Excerpts from e-mails: -Gr?goire: -""" -I can think of a few topics for discussion (non exhaustive): -- your ongoing work on implementing a constraint store in pypy -- transparent distributed computing -- garbage collection -- constraint programming: constraint propagation, modeling, search and - computation spaces. -- logic variables and unification -- lazy computations -- dataflow concurrency (through logic variables or future/promise) -""" - -Roel: -""" -I could give a presentation about Soul, or, more specifically, about -the language integration of Soul. - -Soul is a Prolog implemented in Smalltalk that allows object-oriented -(Smalltalk) code to be executed during logic reasoning. The key -aspect of this symbiosis is what we call the up/down mechanism, which -was previously used by other members of the lab where I did my Ph.D. -(Programming Technology Lab, of the Vrije Universiteit Brussel) for -the prototype-based language Agora (that featured symbiosys with C++, -Java and Smalltalk). In the case of Soul, however, the symbiosis is -between languages of different paradigms. The up/down scheme is -similar to what is used in the object space in PyPy. So lots of -things are touching. - -Note that the integration of Soul with Smalltalk is different than -what happens in Oz, since I explicitly wanted to have two languages -in symbiosis (e.g. I did not want to change Smalltalk). -""" - -Peter: -""" -- Mozart design philosophy vs. Python design philosophy -- How a little bit of formal semantics can help a lot. The Mozart -philosophy is based on having - *two* things at all times: an efficient implementation and a simple -formal semantics. This makes - for an interesting balancing act, but the result is worth it I think. -- Concurrent programming: lightweight concurrency and support for -asynchronous messages are - really very important if you want to "future-proof" Python. Monitors -are terrible; transactions - are nice if you can support them in the language. -- Distributed computing: A single bullet does not do it justice by a -long shot. There are lots - of issues: degree of transparency, language design, distributed -algorithms, fault tolerance, - openness, security. - -There are slides on much of this, but I can present a lot just by -talking and writing on a -whiteboard and answering your questions (helped by Raph and Kevin and -the others in -our group). That will let you direct the discussion. -""" - -Nicolas: -""" -In my opinion: -> ->* Presenting PyPy is needed. -> ->* Presenting our ongoing work about adding logic programming to Python -> is needed. -> ->* Our goal is to add new programming approaches/paradigms to Python -> and we would have a lot to learn from your experience with Oz. What -> is possible and how far can we go with the current langage -> definition? How to design/enhance Python with logic and keep a -> consistent langage? -> ->Among the above topics cited by Gregoire, everything is of interest ->and several are already researched: -> ->* PyPy will have a framework for experimenting with GC ->* PyPy has lazy computation through a Thunk ObjectSpace (pypy slang) ->* PyPy has some concurrency inherited from Stackless Python ->* PyPy plans to do some transparent distribution (end of 2006) - -""" - -Aur?lien: -""" -It might be worthwhile to complete this with the current state of our -plans to "inject" some parts of Oz into PyPy. When this session will -happen, I expect that we will have a working prototype, written in full -Python, that covers the following : - -- a constraint store (kind of first-class environment holding up - variables, domains and constraints) which knows how to bind and unify variables, - and how to propagate constraints on the domains (AC3) -- dataflow variables (with method on them that give (Python, ie OS-threads) thread - access the wait-til-bound semantics, multiple albeit monotonic binding - of compatible/unifiable values) and streams -- computation space (embeds/extends a constraint store, provides the - operators defined in CTM) -- sample search strategies & distributors -- sample problems exercizing the prototype - -This is the subset of Oz we believe covers logic and constraint -programming. Other aspects of Oz, while important and fascinating, will -not be considered in our implementation attempt at this stage. - -The prototype will be, when completed, the basis of a port of these Oz -features to PyPy. How it will be integrated, implementation-wise, -remains unknown to us; to decide what feature will be allowed to "leak" -from one world to the other depends on a clear understanding of how Oz -itself manages the relation between stateful programming and the -declarative parts. -""" - -Peter's answer: -""" -Ok, I see: you are focusing on constraint programming. This is -absolutely fine. -There are three levels you can go here, as I see it: -- Just add lightweight concurrency and dataflow variables. This -provides many - interesting idioms already -- see, e.g., the paper on Flow Java which -adds this - to Java by changing the compiler & VM slightly (see -http://www.sics.se/~frej/flow_java/). -- Add WaitNeeded to the first level. This adds lazy evaluation in a -very nice way. - The combination of dataflow concurrency and lazy evaluation is very -powerful; it goes - beyond what a language with a tighter evaluation strategy can express -(such as Haskell - with its nonstrict strategy). -- Add computation spaces to the first level. This gives a full-fledged -compositional - constraint logic language. It goes much beyond Prolog in that it has -a first-class top - level and lazy versions of bagof (even without lazy evaluation in the -language; with - lazy evaluation it just becomes more concise). -Note that lightweight concurrency is a prerequisite to constraint -programming: each -operational version of a constraint (what we call a "propagator") -executes in its own -thread, and in big constraint problems there can easily be tens of -thousands of these. -""" - -Carl: -""" -On the other hand, since Oz/Mozart contains -interesting security features as well, it might also be interesting to do a -bit of work/talking with the Oz people in this direction. -""" +Gr?goire:: + + I can think of a few topics for discussion (non exhaustive): + - your ongoing work on implementing a constraint store in pypy + - transparent distributed computing + - garbage collection + - constraint programming: constraint propagation, modeling, search and + computation spaces. + - logic variables and unification + - lazy computations + - dataflow concurrency (through logic variables or future/promise) + +Roel:: + + I could give a presentation about Soul, or, more specifically, about + the language integration of Soul. + + Soul is a Prolog implemented in Smalltalk that allows object-oriented + (Smalltalk) code to be executed during logic reasoning. The key + aspect of this symbiosis is what we call the up/down mechanism, which + was previously used by other members of the lab where I did my Ph.D. + (Programming Technology Lab, of the Vrije Universiteit Brussel) for + the prototype-based language Agora (that featured symbiosys with C++, + Java and Smalltalk). In the case of Soul, however, the symbiosis is + between languages of different paradigms. The up/down scheme is + similar to what is used in the object space in PyPy. So lots of + things are touching. + + Note that the integration of Soul with Smalltalk is different than + what happens in Oz, since I explicitly wanted to have two languages + in symbiosis (e.g. I did not want to change Smalltalk). + + +Peter:: + + - Mozart design philosophy vs. Python design philosophy + - How a little bit of formal semantics can help a lot. The Mozart + philosophy is based on having + *two* things at all times: an efficient implementation and a simple + formal semantics. This makes + for an interesting balancing act, but the result is worth it I think. + - Concurrent programming: lightweight concurrency and support for + asynchronous messages are + really very important if you want to "future-proof" Python. Monitors + are terrible; transactions + are nice if you can support them in the language. + - Distributed computing: A single bullet does not do it justice by a + long shot. There are lots + of issues: degree of transparency, language design, distributed + algorithms, fault tolerance, + openness, security. + + There are slides on much of this, but I can present a lot just by + talking and writing on a + whiteboard and answering your questions (helped by Raph and Kevin and + the others in + our group). That will let you direct the discussion. + + +Nicolas:: + + In my opinion: + > + >* Presenting PyPy is needed. + > + >* Presenting our ongoing work about adding logic programming to Python + > is needed. + > + >* Our goal is to add new programming approaches/paradigms to Python + > and we would have a lot to learn from your experience with Oz. What + > is possible and how far can we go with the current langage + > definition? How to design/enhance Python with logic and keep a + > consistent langage? + > + >Among the above topics cited by Gregoire, everything is of interest + >and several are already researched: + > + >* PyPy will have a framework for experimenting with GC + >* PyPy has lazy computation through a Thunk ObjectSpace (pypy slang) + >* PyPy has some concurrency inherited from Stackless Python + >* PyPy plans to do some transparent distribution (end of 2006) + + + +Aur?lien:: + + It might be worthwhile to complete this with the current state of our + plans to "inject" some parts of Oz into PyPy. When this session will + happen, I expect that we will have a working prototype, written in full + Python, that covers the following : + + - a constraint store (kind of first-class environment holding up + variables, domains and constraints) which knows how to bind and unify variables, + and how to propagate constraints on the domains (AC3) + - dataflow variables (with method on them that give (Python, ie OS-threads) thread + access the wait-til-bound semantics, multiple albeit monotonic binding + of compatible/unifiable values) and streams + - computation space (embeds/extends a constraint store, provides the + operators defined in CTM) + - sample search strategies & distributors + - sample problems exercizing the prototype + + This is the subset of Oz we believe covers logic and constraint + programming. Other aspects of Oz, while important and fascinating, will + not be considered in our implementation attempt at this stage. + + The prototype will be, when completed, the basis of a port of these Oz + features to PyPy. How it will be integrated, implementation-wise, + remains unknown to us; to decide what feature will be allowed to "leak" + from one world to the other depends on a clear understanding of how Oz + itself manages the relation between stateful programming and the + declarative parts. + + +Peter's answer:: + + Ok, I see: you are focusing on constraint programming. This is + absolutely fine. + There are three levels you can go here, as I see it: + - Just add lightweight concurrency and dataflow variables. This + provides many + interesting idioms already -- see, e.g., the paper on Flow Java which + adds this + to Java by changing the compiler & VM slightly (see + http://www.sics.se/~frej/flow_java/). + - Add WaitNeeded to the first level. This adds lazy evaluation in a + very nice way. + The combination of dataflow concurrency and lazy evaluation is very + powerful; it goes + beyond what a language with a tighter evaluation strategy can express + (such as Haskell + with its nonstrict strategy). + - Add computation spaces to the first level. This gives a full-fledged + compositional + constraint logic language. It goes much beyond Prolog in that it has + a first-class top + level and lazy versions of bagof (even without lazy evaluation in the + language; with + lazy evaluation it just becomes more concise). + Note that lightweight concurrency is a prerequisite to constraint + programming: each + operational version of a constraint (what we call a "propagator") + executes in its own + thread, and in big constraint problems there can easily be tens of + thousands of these. + + +Carl:: + + On the other hand, since Oz/Mozart contains + interesting security features as well, it might also be interesting to do a + bit of work/talking with the Oz people in this direction. + From cfbolz at codespeak.net Thu Mar 16 01:46:25 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 01:46:25 +0100 (CET) Subject: [pypy-svn] r24416 - pypy/extradoc/pypy.org Message-ID: <20060316004625.AA1791007C@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 01:46:16 2006 New Revision: 24416 Added: pypy/extradoc/pypy.org/ist.png (contents, props changed) Modified: pypy/extradoc/pypy.org/confrest.py Log: use IST logo instead of generic EU logo Modified: pypy/extradoc/pypy.org/confrest.py ============================================================================== --- pypy/extradoc/pypy.org/confrest.py (original) +++ pypy/extradoc/pypy.org/confrest.py Thu Mar 16 01:46:16 2006 @@ -24,8 +24,8 @@ src="http://codespeak.net/pypy/img/py-web1.png", height=110, width=149)), html.img(alt="EU Logo", id="extraimg", - src="eu-logo-small.jpg", - height=105, width=154), + src="ist.png", + height=105, width=213), ) Page = PyPyPage Added: pypy/extradoc/pypy.org/ist.png ============================================================================== Binary file. No diff available. From cfbolz at codespeak.net Thu Mar 16 01:52:07 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 01:52:07 +0100 (CET) Subject: [pypy-svn] r24417 - pypy/dist/pypy/doc/weekly Message-ID: <20060316005207.1239F10086@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 01:52:02 2006 New Revision: 24417 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: feeble start of a description about the logic sprint Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Thu Mar 16 01:52:02 2006 @@ -28,6 +28,21 @@ The Logic Sprint ================ +Last week there was a PyPy-sprint at the UCL in Louvain-la-Neuve. It's main +topic was logic and constraint programming in PyPy. Two of the sprint days were +devoted to discussions with some researchers at the UCL who are heavily +involved with the Oz programming language. The discussions were fruitful and +very stimulating. For more details see the `logic sprint report'_ + +The Logic Object Space +----------------------- + +One of the more visible results of the sprint is the Logic Object Space, a very +small (in terms of lines of code) object space that implements dataflow +variables similar to what Oz has in Python. XXX more + +.. _`logic sprint report`: http://codespeak.net/pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.html + Garbage Collection ================== From tismer at codespeak.net Thu Mar 16 04:38:24 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 16 Mar 2006 04:38:24 +0100 (CET) Subject: [pypy-svn] r24421 - pypy/dist/pypy/translator/tool Message-ID: <20060316033824.D999410082@code0.codespeak.net> Author: tismer Date: Thu Mar 16 04:38:12 2006 New Revision: 24421 Modified: pypy/dist/pypy/translator/tool/cbuild.py Log: cleanup an old attempt to get debuggasble builds Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Thu Mar 16 04:38:12 2006 @@ -95,7 +95,6 @@ # ensure correct math on windows if sys.platform == 'win32': extra_compile_args.append('/Op') # get extra precision - extra_compile_args.append('/PDB:laber') # create debug info if get_default_compiler() == 'unix': old_version = False try: From tismer at codespeak.net Thu Mar 16 04:39:32 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 16 Mar 2006 04:39:32 +0100 (CET) Subject: [pypy-svn] r24422 - in pypy/dist/pypy/rpython/memory: . test Message-ID: <20060316033932.CD57310085@code0.codespeak.net> Author: tismer Date: Thu Mar 16 04:39:21 2006 New Revision: 24422 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: added new operations to gctransform which control extra liveness of objects Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 16 04:39:21 2006 @@ -109,6 +109,8 @@ ops, cleanup_before_exception = res except ValueError: ops, cleanup_before_exception, num_ops_after_exc_raising = res + if not ops: + continue # may happen when we eat gc_increase_aliveness etc. newops.extend(ops) op = ops[-1-num_ops_after_exc_raising] # XXX for now we assume that everything can raise @@ -212,6 +214,14 @@ result = varoftype(lltype.Void) return [SpaceOperation("gc_pop_alive_pyobj", [var], result)] + def replace_gc_protect(self, op, livevars): + """ protect this object from gc (make it immortal) """ + return [], [] + + def replace_gc_unprotect(self, op, livevars): + """ get this object back into gc control """ + return [], [] + def annotate_helper(self, ll_helper, ll_args, ll_result): assert not self.finished args_s = map(annmodel.lltype_to_annotation, ll_args) @@ -354,6 +364,14 @@ varoftype(lltype.Void), cleanup=None)) return result + def replace_gc_protect(self, op, livevars): + """ protect this object from gc (make it immortal) """ + return self.push_alive(op.args[0]), [] + + def replace_gc_unprotect(self, op, livevars): + """ get this object back into gc control """ + return self.pop_alive(op.args[0]), [] + def replace_setfield(self, op, livevars): if not var_needsgc(op.args[2]): return [op], [] Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Thu Mar 16 04:39:21 2006 @@ -4,6 +4,8 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.lltypesystem import lltype from pypy.objspace.flow.model import Variable +from pypy.annotation import model as annmodel +from pypy.rpython import extregistry from pypy import conftest import py @@ -214,6 +216,33 @@ elif op.opname == 'gc_pop_alive_pyobj': pop_count += 1 assert push_count == 0 and pop_count == 1 + +def test_protect_unprotect(): + def protect(obj): RaiseNameError + def unprotect(obj): RaiseNameError + def rtype_protect(hop): + v_any, = hop.inputargs(hop.args_r[0]) + return hop.genop('gc_protect', [v_any], resulttype=lltype.Void) + def rtype_unprotect(hop): + v_any, = hop.inputargs(hop.args_r[0]) + return hop.genop('gc_unprotect', [v_any], resulttype=lltype.Void) + extregistry.register_value(protect, + compute_result_annotation=annmodel.s_None, specialize_call=rtype_protect) + extregistry.register_value(unprotect, + compute_result_annotation=annmodel.s_None, specialize_call=rtype_unprotect) + + def p(): protect('this is an object') + def u(): unprotect('this is an object') + + rgc = gctransform.RefcountingGCTransformer + bgc = gctransform.BoehmGCTransformer + expected = [1, 1, 0, 0] + gcs = [rgc, rgc, bgc, bgc] + fs = [p, u, p, u] + for ex, f, gc in zip(expected, fs, gcs): + t, transformer = rtype_and_transform(f, [], gc, check=False) + ops = getops(graphof(t, f)) + assert len(ops.get('direct_call', [])) == ex def test_except_block(): S = lltype.GcStruct("S", ('x', lltype.Signed)) From tismer at codespeak.net Thu Mar 16 05:24:54 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 16 Mar 2006 05:24:54 +0100 (CET) Subject: [pypy-svn] r24423 - pypy/dist/pypy/rpython/memory Message-ID: <20060316042454.56F141007E@code0.codespeak.net> Author: tismer Date: Thu Mar 16 05:24:37 2006 New Revision: 24423 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: false comment Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 16 05:24:37 2006 @@ -110,7 +110,7 @@ except ValueError: ops, cleanup_before_exception, num_ops_after_exc_raising = res if not ops: - continue # may happen when we eat gc_increase_aliveness etc. + continue # may happen when we eat gc_protect/gc_unprotect. newops.extend(ops) op = ops[-1-num_ops_after_exc_raising] # XXX for now we assume that everything can raise From tismer at codespeak.net Thu Mar 16 08:33:23 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 16 Mar 2006 08:33:23 +0100 (CET) Subject: [pypy-svn] r24429 - in pypy/dist/pypy: interpreter module/stackless Message-ID: <20060316073323.2CE5D10082@code0.codespeak.net> Author: tismer Date: Thu Mar 16 08:33:13 2006 New Revision: 24429 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/module/stackless/coroutine.py Log: added subcontext support for coroutines. Problem: I cannot get it to annotate, the stack is SomeObject. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 16 08:33:13 2006 @@ -15,13 +15,6 @@ self.ticker = 0 self.compiler = space.createcompiler() - # XXX - # I think that it is wrong to hide frames here. The stack should - # contain all the frames, because we need them for pickling. - # better to do the hiding when the stack is accessed. This implies that - # we have an explicit frame depth counter. - # please comment/correct me! (chris) - def enter(self, frame): if self.framestack.depth() > self.space.sys.recursionlimit: raise OperationError(self.space.w_RuntimeError, @@ -41,9 +34,21 @@ if not frame.hide(): self.framestack.pop() - # coroutine support - # XXX still trying and thinking hard - + # coroutine: subcontext support + def subcontext_new(coobj): + coobj.framestack = Stack() + coobj.w_tracefunc = None + coobj.w_profilefunc = None + coobj.is_tracing = 0 + new_subcontext = staticmethod(new_subcontext) + + def subcontext_swap(self, coobj): + self.framestack, coobj.framestack = coobj.framestack, self.framestack + self.w_tracefunc, coobj.w_tracefunc = coobj.w_tracefunc, self.w_tracefunc + self.w_profilefunc, coobj.w_profilefunc = coobj.w_profilefunc, self.w_profilefunc + self.is_tracing, coobj.is_tracing = coobj.is_tracing, self.is_tracing + # coroutine: I think this is all, folks! + def get_builtin(self): try: return self.framestack.top().builtin Modified: pypy/dist/pypy/module/stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/coroutine.py (original) +++ pypy/dist/pypy/module/stackless/coroutine.py Thu Mar 16 08:33:13 2006 @@ -50,6 +50,7 @@ state = self._get_state(space) Coroutine.__init__(self, state) self.flags = 0 + space.getexecutioncontext().subcontext_new(self) def descr_method__new__(space, w_subtype): co = space.allocate_instance(AppCoroutine, w_subtype) @@ -75,7 +76,10 @@ raise OperationError(space.w_ValueError, space.wrap( "cannot switch to an unbound Coroutine")) state = self.costate + ec = space.getexecutioncontext() + ec.subcontext_switch(state.current, self) self.switch() + ec.subcontext_switch(state.last, state.current) w_ret, state.w_tempval = state.w_tempval, space.w_None return w_ret From ac at codespeak.net Thu Mar 16 10:25:30 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Mar 2006 10:25:30 +0100 (CET) Subject: [pypy-svn] r24432 - pypy/dist/pypy/interpreter Message-ID: <20060316092530.03F5410082@code0.codespeak.net> Author: ac Date: Thu Mar 16 10:25:30 2006 New Revision: 24432 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: Fix typo Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 16 10:25:30 2006 @@ -40,7 +40,7 @@ coobj.w_tracefunc = None coobj.w_profilefunc = None coobj.is_tracing = 0 - new_subcontext = staticmethod(new_subcontext) + subcontext_new = staticmethod(subcontext_new) def subcontext_swap(self, coobj): self.framestack, coobj.framestack = coobj.framestack, self.framestack From auc at codespeak.net Thu Mar 16 10:33:00 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 16 Mar 2006 10:33:00 +0100 (CET) Subject: [pypy-svn] r24433 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060316093300.006051008F@code0.codespeak.net> Author: auc Date: Thu Mar 16 10:32:58 2006 New Revision: 24433 Added: pypy/dist/pypy/lib/logic/computation_space/solvers.py - copied unchanged from r24429, pypy/dist/pypy/lib/logic/computation_space/strategies.py Removed: pypy/dist/pypy/lib/logic/computation_space/strategies.py Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: renaming Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Thu Mar 16 10:32:58 2006 @@ -71,7 +71,7 @@ #-- computation spaces ------------------------------- -import strategies +import solvers class TestComputationSpace: @@ -145,14 +145,14 @@ assert res.values() == [0, 0, 0] def test_scheduling_dfs_one_solution(self): - sol = strategies.dfs_one(problems.conference_scheduling) + sol = solvers.dfs_one(problems.conference_scheduling) spc = space.ComputationSpace(problems.conference_scheduling) assert spc.test_solution( sol ) def test_scheduling_all_solutions_dfs(self): - sols = strategies.solve_all(problems.conference_scheduling) + sols = solvers.solve_all(problems.conference_scheduling) assert len(sols) == 64 spc = space.ComputationSpace(problems.conference_scheduling) for s in sols: @@ -161,12 +161,12 @@ def test_scheduling_all_solutions_lazily_dfs(self): sp = space.ComputationSpace(problems.conference_scheduling) - for sol in strategies.lazily_solve_all(sp): + for sol in solvers.lazily_solve_all(sp): assert sp.test_solution(sol) def test_scheduling_all_solutions_bfs(self): - sols = strategies.solve_all(problems.conference_scheduling, - direction=strategies.Breadth) + sols = solvers.solve_all(problems.conference_scheduling, + direction=solvers.Breadth) assert len(sols) == 64 spc = space.ComputationSpace(problems.conference_scheduling) for s in sols: @@ -175,11 +175,11 @@ def test_scheduling_all_solutions_lazily_bfs(self): sp = space.ComputationSpace(problems.conference_scheduling) - for sol in strategies.lazily_solve_all(sp, direction=strategies.Breadth): + for sol in solvers.lazily_solve_all(sp, direction=solvers.Breadth): assert sp.test_solution(sol) - def test_sudoku(self): + def notest_sudoku(self): spc = newspace(problems.sudoku) print spc.constraints @@ -198,7 +198,7 @@ spc.inject(more_constraints) print spc.constraints - sol_iter = strategies.lazily_solve_all(spc) + sol_iter = solvers.lazily_solve_all(spc) sol = sol_iter.next() print sol assert spc.test_solution(sol) From nik at codespeak.net Thu Mar 16 11:10:21 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 11:10:21 +0100 (CET) Subject: [pypy-svn] r24438 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316101021.201791008F@code0.codespeak.net> Author: nik Date: Thu Mar 16 11:10:19 2006 New Revision: 24438 Added: pypy/dist/pypy/translator/squeak/opformatter.py Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: rip out the code generation for llops and put it in its own module. somewhat improve handling of the various integer types. there's still some quite ugly code around. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 11:10:19 2006 @@ -3,8 +3,8 @@ from pypy.objspace.flow.model import last_exception, checkgraph from pypy.translator.gensupp import NameManager from pypy.translator.squeak.message import Message, camel_case +from pypy.translator.squeak.opformatter import OpFormatter from pypy.rpython.ootypesystem.ootype import Instance, ROOT -from pypy.rpython.rarithmetic import r_int, r_uint from pypy import conftest try: set @@ -196,46 +196,6 @@ class CallableNode(CodeNode): - selectormap = { - #'setitem:with:': 'at:put:', - #'getitem:': 'at:', - 'new': 'new', - 'runtimenew': 'new', - 'classof': 'class', - 'sameAs': 'yourself', - } - - primitive_ops = { - 'abs': 'abs', - 'is_true': 'isZero not', - 'neg': 'negated', - 'invert': 'bitInvert', # maybe bitInvert32? - - 'add': '+', - 'sub': '-', - 'eq': '=', - 'mul': '*', - 'div': '//', - 'floordiv': '//', - } - - primitive_opprefixes = "int", "uint", "llong", "ullong", "float" - - primitive_wrapping_ops = "neg", "invert", "add", "sub", "mul" - - primitive_masks = { - # XXX horrendous, but I can't figure out how to do this cleanly - "int": (Message("maskInt"), - """maskInt: i - ((i <= %s) & (i >= %s)) ifTrue: [^i]. - ^ i + %s \\\\ %s - %s - """ % (sys.maxint, -sys.maxint-1, - sys.maxint+1, 2*(sys.maxint+1), sys.maxint+1)), - "uint": (Message("maskUint"), - """maskUint: i - ^ i bitAnd: %s""" % r_uint.MASK), - } - def render_body(self, startblock): self.loops = LoopFinder(startblock).loops args = self.arguments(startblock) @@ -260,93 +220,6 @@ else: raise TypeError, "expr(%r)" % (v,) - def oper(self, op): - opname_parts = op.opname.split("_") - if opname_parts[0] in self.primitive_opprefixes: - return self.oper_primitive( - op, opname_parts[0], "_".join(opname_parts[1:])) - op_method = getattr(self, "op_%s" % op.opname, None) - if op_method is not None: - return op_method(op) - else: - name = op.opname - receiver = self.expr(op.args[0]) - args = [self.expr(arg) for arg in op.args[1:]] - return self.assignment(op, receiver, name, args) - - def oper_primitive(self, op, ptype, opname): - receiver = self.expr(op.args[0]) - args = [self.expr(arg) for arg in op.args[1:]] - sel = Message(self.primitive_ops[opname]) - message = "%s %s" % (receiver, sel.signature(args)) - if opname in self.primitive_wrapping_ops \ - and self.primitive_masks.has_key(ptype): - mask_selector, mask_code = self.primitive_masks[ptype] - helper = HelperNode(self.gen, mask_selector, mask_code) - message = helper.apply(["(%s)" % message]) - self.gen.schedule_node(helper) - return "%s := %s." % (self.expr(op.result), message) - - def assignment(self, op, receiver_name, sel_name, arg_names): - sel_name = camel_case(sel_name) - if op.opname != "oosend": - sel_name = self.selectormap.get(sel_name, sel_name) - sel = Message(sel_name) - return "%s := %s %s." % (self.expr(op.result), - receiver_name, sel.signature(arg_names)) - - def op_oosend(self, op): - message = op.args[0].value - if hasattr(self, "self") and op.args[1] == self.self: - receiver = "self" - else: - receiver = self.expr(op.args[1]) - args = [self.expr(a) for a in op.args[2:]] - self.gen.schedule_node( - MethodNode(self.gen, op.args[1].concretetype, message)) - return self.assignment(op, receiver, message, args) - - def op_oogetfield(self, op): - INST = op.args[0].concretetype - receiver = self.expr(op.args[0]) - field_name = self.unique_field(INST, op.args[1].value) - if hasattr(self, "self") and op.args[0] == self.self: - # Private field access - # Could also directly substitute op.result with name - # everywhere for optimization. - return "%s := %s." % (self.expr(op.result), camel_case(field_name)) - else: - # Public field access - self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) - return self.assignment(op, receiver, field_name, []) - - def op_oosetfield(self, op): - # Note that the result variable is never used - INST = op.args[0].concretetype - field_name = self.unique_field(INST, op.args[1].value) - field_value = self.expr(op.args[2]) - if hasattr(self, "self") and op.args[0] == self.self: - # Private field access - return "%s := %s." % (field_name, field_value) - else: - # Public field access - self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) - receiver = self.expr(op.args[0]) - return "%s %s: %s." % (receiver, field_name, field_value) - - def op_oodowncast(self, op): - return "%s := %s." % (self.expr(op.result), self.expr(op.args[0])) - - def op_direct_call(self, op): - # XXX not sure if static methods of a specific class should - # be treated differently. - receiver = "PyFunctions" - callable_name = self.expr(op.args[0]) - args = [self.expr(a) for a in op.args[1:]] - self.gen.schedule_node( - FunctionNode(self.gen, op.args[0].value.graph)) - return self.assignment(op, receiver, callable_name, args) - def render_return(self, args): if len(args) == 2: # exception @@ -373,8 +246,9 @@ yield '"skip1"' return yield "[" + formatter = OpFormatter(self.gen, self) for op in block.operations: - yield "%s" % self.oper(op) + yield "%s" % formatter.format(op) if len(block.exits) == 0: for line in self.render_return(block.inputargs): yield line @@ -410,6 +284,7 @@ self.gen = gen self.INSTANCE = INSTANCE self.name = method_name + self.self = None # Will be set upon rendering self.hash_key = (INSTANCE, method_name) def dependencies(self): @@ -435,6 +310,7 @@ self.gen = gen self.graph = graph self.name = gen.nameof(graph.func) + self.self = None self.hash_key = graph def dependencies(self): Added: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 11:10:19 2006 @@ -0,0 +1,164 @@ +import sys +from pypy.objspace.flow.model import Constant, Variable +from pypy.rpython.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong +from pypy.rpython.ootypesystem.ootype import Instance +from pypy.translator.squeak.message import Message, camel_case + +def _setup_int_masks(): + """Generates code for helpers to mask the various integer types.""" + masks = {} + for name, r_type in ("int", r_int), ("uint", r_uint), \ + ("llong", r_longlong), ("ullong", r_ulonglong): + helper_name = "mask%s" % name.capitalize() + if name[0] == "u": + # Unsigned integer type + code = """%s: i + ^ i bitAnd: %s""" % (helper_name, r_type.MASK) + else: + # Signed integer type + code = """%s: i + (i <= %s) & (i >= %s) ifTrue: [^i]. + (i < 0) ifTrue: [^i bitAnd: %s] + ifFalse: [^(((i negated) - 1) bitAnd: %s) negated - 1] + """ % (helper_name, r_type.MASK>>1, -(r_type.MASK>>1)-1, + r_type.MASK>>1, r_type.MASK>>1) + masks[name] = helper_name, code + return masks + +class OpFormatter: + + ops = { + 'new': 'new', + 'runtimenew': 'new', + 'classof': 'class', + 'same_as': 'yourself', + } + + number_ops = { + 'abs': 'abs', + 'is_true': 'isZero not', + 'neg': 'negated', + 'invert': 'bitInvert', # maybe bitInvert32? + + 'add': '+', + 'sub': '-', + 'eq': '=', + 'mul': '*', + 'div': '//', + 'floordiv': '//', + } + + number_opprefixes = "int", "uint", "llong", "ullong", "float" + + wrapping_ops = "neg", "invert", "add", "sub", "mul" + + int_masks = _setup_int_masks() + + def __init__(self, gen, node): + self.gen = gen + self.node = node + + def expr(self, v): + # XXX this code duplicated in gensqueak.py + if isinstance(v, Variable): + return camel_case(v.name) + elif isinstance(v, Constant): + if isinstance(v.concretetype, Instance): + const_id = self.gen.unique_name( + v, "const_%s" % self.gen.nameof(v.value._TYPE)) + self.gen.constant_insts[v] = const_id + return "(PyConstants getConstant: '%s')" % const_id + return self.gen.nameof(v.value) + else: + raise TypeError, "expr(%r)" % (v,) + + def format(self, op): + opname_parts = op.opname.split("_") + if opname_parts[0] in self.number_opprefixes: + return self.format_number_op( + op, opname_parts[0], "_".join(opname_parts[1:])) + op_method = getattr(self, "op_%s" % op.opname, None) + if op_method is not None: + return op_method(op) + else: + name = op.opname + name = self.ops.get(name, name) + receiver = self.expr(op.args[0]) + args = [self.expr(arg) for arg in op.args[1:]] + return self.assignment(op, receiver, name, args) + + def format_number_op(self, op, ptype, opname): + receiver = self.expr(op.args[0]) + args = [self.expr(arg) for arg in op.args[1:]] + sel = Message(self.number_ops[opname]) + message = "%s %s" % (receiver, sel.signature(args)) + if opname in self.wrapping_ops \ + and self.int_masks.has_key(ptype): + from pypy.translator.squeak.gensqueak import HelperNode + mask_name, mask_code = self.int_masks[ptype] + helper = HelperNode(self.gen, Message(mask_name), mask_code) + message = helper.apply(["(%s)" % message]) + self.gen.schedule_node(helper) + return "%s := %s." % (self.expr(op.result), message) + + def assignment(self, op, receiver_name, sel_name, arg_names): + sel = Message(sel_name) + return "%s := %s %s." % (self.expr(op.result), + receiver_name, sel.signature(arg_names)) + + def op_oosend(self, op): + message = op.args[0].value + if op.args[1] == self.node.self: + receiver = "self" + else: + receiver = self.expr(op.args[1]) + args = [self.expr(a) for a in op.args[2:]] + from pypy.translator.squeak.gensqueak import MethodNode + self.gen.schedule_node( + MethodNode(self.gen, op.args[1].concretetype, message)) + return self.assignment(op, receiver, message, args) + + def op_oogetfield(self, op): + INST = op.args[0].concretetype + receiver = self.expr(op.args[0]) + field_name = self.node.unique_field(INST, op.args[1].value) + if op.args[0] == self.node.self: + # Private field access + # Could also directly substitute op.result with name + # everywhere for optimization. + return "%s := %s." % (self.expr(op.result), field_name) + else: + # Public field access + from pypy.translator.squeak.gensqueak import GetterNode + self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) + return self.assignment(op, receiver, field_name, []) + + def op_oosetfield(self, op): + # Note that the result variable is never used + INST = op.args[0].concretetype + field_name = self.node.unique_field(INST, op.args[1].value) + field_value = self.expr(op.args[2]) + if op.args[0] == self.node.self: + # Private field access + return "%s := %s." % (field_name, field_value) + else: + # Public field access + from pypy.translator.squeak.gensqueak import SetterNode + self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) + receiver = self.expr(op.args[0]) + return "%s %s: %s." % (receiver, field_name, field_value) + + def op_oodowncast(self, op): + return "%s := %s." % (self.expr(op.result), self.expr(op.args[0])) + + def op_direct_call(self, op): + # XXX not sure if static methods of a specific class should + # be treated differently. + from pypy.translator.squeak.gensqueak import FunctionNode + receiver = "PyFunctions" + callable_name = self.expr(op.args[0]) + args = [self.expr(a) for a in op.args[1:]] + self.gen.schedule_node( + FunctionNode(self.gen, op.args[0].value.graph)) + return self.assignment(op, receiver, callable_name, args) + Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Thu Mar 16 11:10:19 2006 @@ -11,7 +11,6 @@ RESTYPE = testcase[1] args = testcase[2:] - llopfunc = getattr(llop, llopname) arg_signature = ", ".join(["v%s" % n for n in range(len(args))]) exec """def lloptest(%s): return llop.%s(%s, %s)""" \ From arigo at codespeak.net Thu Mar 16 12:05:03 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Mar 2006 12:05:03 +0100 (CET) Subject: [pypy-svn] r24447 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060316110503.6889D10091@code0.codespeak.net> Author: arigo Date: Thu Mar 16 12:04:54 2006 New Revision: 24447 Added: pypy/extradoc/sprintinfo/leysin-winter-2006/ (props changed) pypy/extradoc/sprintinfo/leysin-winter-2006/announcement.txt (contents, props changed) pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (contents, props changed) Log: Leysin sprint information. Added: pypy/extradoc/sprintinfo/leysin-winter-2006/announcement.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/announcement.txt Thu Mar 16 12:04:54 2006 @@ -0,0 +1,60 @@ +============================================== +Leysin Internal Winter Sprint (3-9 April 2006) +============================================== + +The next PyPy sprint will be in Leysin, Switzerland, for the second +time. Its main focus is progressing in the core PyPy areas. This +sprint is "internal" in the sense that we would like to concentrate on +areas that are not terribly newcomer-friendly, so prior knowledge in +PyPy is definitely required. (A priori, it is not closed to people +outside the "official" core developers group, though.) + +Goals and topics of the sprint +------------------------------ + +It so happens that the sprint goals can be summarized in two opposite +statements: + +1. Have fun in winter sports. There is plenty of snow this year, + so skiing will still be great during the sprint. For non-skiers, + there are many winter things to do: walks, ice skating, sledge + and other forms of downhill gliding, etc... The idea would be to + reserve several days for this; ski days end around 4pm, which + still leaves plenty of time for hacking. + +2. Progress on the "core" areas that are critical in our EU-phase-2: + JIT, GC, Tasklet pickling, rctypes, (logic if Logilab people are + here). More specific goals are not necessary: in most areas we + will just continue the on-going effort from wherever it is at the + moment. + +Location & Accomodation +----------------------- + +Leysin, Switzerland, same place as in January 2005. Let me refresh your +memory: both the sprint venue and the logding will be in a very spacious +pair of chalets built specifically for bed & breakfast: +http://www.ermina.ch/. The place has a baseline ADSL Internet connexion +(600Kb) with wireless installed. You can of course arrange your own +lodging anywhere (you cannot be more than a 15 minutes walk away from +the sprint venue), but I definitely recommend to lodge there too -- you +won't find better sights anywhere else (though you probably won't get +much worse ones easily, either :-) + +I made pre-reservations in the Chalet, so please *confirm* quickly that +you are coming so that we can adjust the reservations as appropriate. +We get 2-persons rooms for 60 CHF a night all included, with breakfast. +There are larger rooms too (less expensive, possibly more available too) +and the possibility to get a single room if you really want to. +Depending on availability we might have to juggle a bit dynamically. + +Please register by svn: + + http://codespeak.net/svn/pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt + +Exact times +----------- + +Officially, 3-9 April 2006. Both dates are flexible, you can arrive or +leave earlier or later: I don't expect this to be a problem in such +internal sprints. Added: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Thu Mar 16 12:04:54 2006 @@ -0,0 +1,44 @@ + +People coming to the Leysin sprint Winter 2006 +================================================== + +People who have a ``?`` in their arrive/depart or accomodation +column are known to be coming but there are no details +available yet from them. + +Use ``Accomodation = Ermina`` for the group booking at the Chalets. + +==================== ============== ===================== + Name Arrive/Depart Accomodation +==================== ============== ===================== +Anders Chrigstroem ? Ermina? +Holger Krekel ? Ermina? +Samuele Pedroni ? Ermina? +Armin Rigo -- private +Christian Tismer ? Ermina? +==================== ============== ===================== + +People on the following list were present at previous sprints: + +==================== ============== ===================== + Name Arrive/Depart Accomodation +==================== ============== ===================== +Lene Wagner ? ? +Amaury Forgeot d'Arc ? ? +Valentino Volonghi ? ? +Boris Feigin ? ? +Andrew Thompson ? ? +Bert Freudenberg ? ? +Ludovic Aubry ? ? +Adrien Di Mascio ? ? +Jacob Hallen ? ? +Laura Creighton ? ? +Beatrice Duering ? ? +Eric van Riet Paap ? ? +Michael Hudson ? ? +Carl Friedrich Bolz ? ? +Anders Lehmann ? ? +Niklaus Haldimann ? ? +Richard Emslie ? ? +Johan Hahn ? ? +==================== ============== ===================== From cfbolz at codespeak.net Thu Mar 16 12:24:48 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 12:24:48 +0100 (CET) Subject: [pypy-svn] r24448 - pypy/dist/pypy/translator/backendopt Message-ID: <20060316112448.A5FEE100A3@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 12:24:42 2006 New Revision: 24448 Modified: pypy/dist/pypy/translator/backendopt/inline.py Log: make inlining less braindead and probably faster (thanks michael): look for only the _first_ callsite in a graph, instead of all callsites, when we are only interested in one Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Thu Mar 16 12:24:42 2006 @@ -37,9 +37,8 @@ graphs_or_something[graph] = True return graphs_or_something -def find_callsites(graph, calling_what): - callsites = [] - def visit(block): +def iter_callsites(graph, calling_what): + for block in graph.iterblocks(): if isinstance(block, Block): for i, op in enumerate(block.operations): if not op.opname == "direct_call": @@ -49,16 +48,30 @@ # accept a function or a graph as 'inline_func' if (graph is calling_what or getattr(funcobj, '_callable', None) is calling_what): - callsites.append((graph, block, i)) - traverse(visit, graph) - return callsites + yield graph, block, i + +def find_callsites(graph, calling_what): + return list(iter_callsites(graph, calling_what)) + +def iter_first_callsites(graph, calling_what): + # restart the iter_callsites iterator every time, since the graph might + # have changed + while 1: + iterator = iter_callsites(graph, calling_what) + yield iterator.next() + +def contains_call(graph, calling_what): + try: + iterator = iter_callsites(graph, calling_what) + iterator.next() + return True + except StopIteration: + return False def inline_function(translator, inline_func, graph): - count = 0 - callsites = find_callsites(graph, inline_func) - while callsites != []: - subgraph, block, index_operation = callsites.pop() - if find_callsites(subgraph, subgraph): + for count, (subgraph, block, index_operation) in enumerate( + iter_first_callsites(graph, inline_func)): + if contains_call(subgraph, subgraph): raise CannotInline("inlining a recursive function") operation = block.operations[index_operation] if getattr(operation, "cleanup", None) is not None: @@ -68,7 +81,6 @@ _inline_function(translator, graph, block, index_operation) checkgraph(graph) count += 1 - callsites = find_callsites(graph, inline_func) return count def _find_exception_type(block): From mwh at codespeak.net Thu Mar 16 12:31:27 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 16 Mar 2006 12:31:27 +0100 (CET) Subject: [pypy-svn] r24449 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060316113127.B312A100A6@code0.codespeak.net> Author: mwh Date: Thu Mar 16 12:31:25 2006 New Revision: 24449 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: my details. it looks massively less expensive for me to travel on mondays rather than sundays for some reason (still fairly expensive though...) Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Thu Mar 16 12:31:25 2006 @@ -16,6 +16,7 @@ Samuele Pedroni ? Ermina? Armin Rigo -- private Christian Tismer ? Ermina? +Michael Hudson 4th-10th? Ermina? ==================== ============== ===================== People on the following list were present at previous sprints: From ale at codespeak.net Thu Mar 16 12:40:02 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 16 Mar 2006 12:40:02 +0100 (CET) Subject: [pypy-svn] r24450 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060316114002.C18AE10098@code0.codespeak.net> Author: ale Date: Thu Mar 16 12:40:01 2006 New Revision: 24450 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: My info$ Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Thu Mar 16 12:40:01 2006 @@ -17,6 +17,7 @@ Armin Rigo -- private Christian Tismer ? Ermina? Michael Hudson 4th-10th? Ermina? +Anders Lehmann 2nd-9th Ermina ==================== ============== ===================== People on the following list were present at previous sprints: @@ -38,7 +39,6 @@ Eric van Riet Paap ? ? Michael Hudson ? ? Carl Friedrich Bolz ? ? -Anders Lehmann ? ? Niklaus Haldimann ? ? Richard Emslie ? ? Johan Hahn ? ? From cfbolz at codespeak.net Thu Mar 16 12:52:26 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 12:52:26 +0100 (CET) Subject: [pypy-svn] r24455 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20060316115226.3D5B410098@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 12:52:24 2006 New Revision: 24455 Modified: pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/backendopt/test/test_inline.py Log: off by one error Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Thu Mar 16 12:52:24 2006 @@ -69,8 +69,8 @@ return False def inline_function(translator, inline_func, graph): - for count, (subgraph, block, index_operation) in enumerate( - iter_first_callsites(graph, inline_func)): + count = 0 + for subgraph, block, index_operation in iter_first_callsites(graph, inline_func): if contains_call(subgraph, subgraph): raise CannotInline("inlining a recursive function") operation = block.operations[index_operation] Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_inline.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_inline.py Thu Mar 16 12:52:24 2006 @@ -58,6 +58,8 @@ def check_auto_inlining(func, sig, threshold=None): t = translate(func, sig) + if option.view: + t.view() # inline! sanity_check(t) # also check before inlining (so we don't blame it) if threshold is None: @@ -65,6 +67,8 @@ else: auto_inlining(t, threshold=threshold) sanity_check(t) + if option.view: + t.view() interp = LLInterpreter(t.rtyper) def eval_func(args): return interp.eval_graph(graphof(t, func), args) @@ -85,6 +89,14 @@ result = eval_func([2, 12]) assert result == f(2, 12) +def test_nothing_to_inline(): + def f(): + return 1 + def g(): + return 2 + eval_func = check_inline(g, f, []) + assert eval_func([]) == 1 + def test_inline_big(): def f(x): result = [] From mwh at codespeak.net Thu Mar 16 13:28:56 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 16 Mar 2006 13:28:56 +0100 (CET) Subject: [pypy-svn] r24457 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060316122856.A3D36100AC@code0.codespeak.net> Author: mwh Date: Thu Mar 16 13:28:54 2006 New Revision: 24457 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: oops, i meant the 3rd Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Thu Mar 16 13:28:54 2006 @@ -16,7 +16,7 @@ Samuele Pedroni ? Ermina? Armin Rigo -- private Christian Tismer ? Ermina? -Michael Hudson 4th-10th? Ermina? +Michael Hudson 3rd-10th? Ermina? Anders Lehmann 2nd-9th Ermina ==================== ============== ===================== @@ -37,7 +37,6 @@ Laura Creighton ? ? Beatrice Duering ? ? Eric van Riet Paap ? ? -Michael Hudson ? ? Carl Friedrich Bolz ? ? Niklaus Haldimann ? ? Richard Emslie ? ? From cfbolz at codespeak.net Thu Mar 16 13:57:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 13:57:22 +0100 (CET) Subject: [pypy-svn] r24459 - pypy/dist/pypy/rpython/memory Message-ID: <20060316125722.7FA61100B7@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 13:57:20 2006 New Revision: 24459 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: do a checkgraph at the end of the gc transformation Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 16 13:57:20 2006 @@ -87,6 +87,7 @@ inline.inline_function(self.translator, inline_graph, graph) except inline.CannotInline: pass + checkgraph(graph) def transform_block(self, block): newops = [] From mwh at codespeak.net Thu Mar 16 14:17:03 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 16 Mar 2006 14:17:03 +0100 (CET) Subject: [pypy-svn] r24461 - pypy/dist/pypy/bin Message-ID: <20060316131703.082181008D@code0.codespeak.net> Author: mwh Date: Thu Mar 16 14:16:57 2006 New Revision: 24461 Modified: pypy/dist/pypy/bin/py.py Log: issue189 resolved "py.py #! has extra space at the end" Modified: pypy/dist/pypy/bin/py.py ============================================================================== --- pypy/dist/pypy/bin/py.py (original) +++ pypy/dist/pypy/bin/py.py Thu Mar 16 14:16:57 2006 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python """Main entry point into the PyPy interpreter. For a list of options, type From nik at codespeak.net Thu Mar 16 14:29:28 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 14:29:28 +0100 (CET) Subject: [pypy-svn] r24462 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316132928.056D610091@code0.codespeak.net> Author: nik Date: Thu Mar 16 14:29:22 2006 New Revision: 24462 Added: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/test/test_codeformatter.py Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/opformatter.py Log: decouple the emission of actual squeak syntax from the opformatter. the opformatter now builds up a kind of abstract syntax tree which are then turned into code by the codeformatter. this design yet to be applied to all the nodes. Added: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Thu Mar 16 14:29:22 2006 @@ -0,0 +1,125 @@ +from pypy.objspace.flow.model import Constant, Variable +from pypy.rpython.ootypesystem import ootype + +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) + +class Message: + + def __init__(self, name): + self.name = camel_case(name) # XXX Should not use camel_case here + self.infix = False + if len(name) <= 2 and not name.isalnum(): + # Binary infix selector, e.g. "+" + self.infix = True + + def with_args(self, args): + return MessageWithArgs(self, args) + + def send_to(self, receiver, args): + return self.with_args(args).send_to(receiver) + +class MessageWithArgs: + + def __init__(self, message, args): + self.message = message + self.args = args + + def send_to(self, receiver): + return SentMessage(self, receiver) + +class SentMessage: + + def __init__(self, message_wargs, receiver): + self.message_wargs = message_wargs + self.receiver = receiver + + def assign_to(self, result): + return Assignment(result, self) + +class Assignment: + + def __init__(self, lvalue, rvalue): + self.lvalue = lvalue + self.rvalue = rvalue + +class Self: + + pass + +class Field: + + def __init__(self, name): + self.name = name + +class CodeFormatter: + + def __init__(self, gen=None): # XXX get rid of default argument + self.gen = gen + + def format(self, code): + if isinstance(code, Variable) or isinstance(code, Constant): + return self.format_arg(code) + type_name = code.__class__.__name__ + method = getattr(self, "format_%s" % type_name) + return method(code) + + def format_arg(self, arg): + """Formats Variables and Constants.""" + if isinstance(arg, Variable): + return camel_case(arg.name) + elif isinstance(arg, Constant): + if isinstance(arg.concretetype, ootype.Instance): + # XXX fix this + #const_id = self.gen.unique_name( + # v, "const_%s" % self.gen.nameof(v.value._TYPE)) + #self.gen.constant_insts[v] = const_id + #return "(PyConstants getConstant: '%s')" % const_id + return None + elif arg.concretetype == ootype.Bool: + return str(arg.value).lower() + elif arg.concretetype == ootype.Void: + if isinstance(arg.value, ootype.Instance): + return self.format_Instance(arg.value) + else: + assert arg.value is None + return "nil" + else: + # Integers etc. + return str(arg.value) + else: + raise TypeError, "No representation for argument %r" % (v,) + + def format_Instance(self, INSTANCE): + return self.gen.nameof_Instance(INSTANCE) + + def format_Self(self, _): + return "self" + + def format_Field(self, field): + return field.name + + def format_MessageWithArgs(self, message): + name = message.message.name + arg_count = len(message.args) + if arg_count == 0: + return name + elif message.message.infix: + assert arg_count == 1 + return "%s %s" % (name, self.format(message.args[0])) + else: + parts = [name] + if arg_count > 1: + parts += ["with"] * (arg_count - 1) + return " ".join(["%s: %s" % (p, self.format(a)) + for (p, a) in zip(parts, message.args)]) + + def format_SentMessage(self, smessage): + return "(%s %s)" % (self.format(smessage.receiver), + self.format_MessageWithArgs(smessage.message_wargs)) + + def format_Assignment(self, ass): + return "%s := %s" % (self.format(ass.lvalue), self.format(ass.rvalue)) + Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 14:29:22 2006 @@ -248,7 +248,7 @@ yield "[" formatter = OpFormatter(self.gen, self) for op in block.operations: - yield "%s" % formatter.format(op) + yield "%s." % formatter.format(op) if len(block.exits) == 0: for line in self.render_return(block.inputargs): yield line @@ -357,14 +357,14 @@ HELPERS = Instance("Helpers", ROOT) - def __init__(self, gen, selector, code): + def __init__(self, gen, message, code): self.gen = gen - self.selector = selector + self.message = message self.code = code self.hash_key = ("helper", code) def apply(self, args): - return "PyHelpers %s" % self.selector.signature(args) + return self.message.send_to(self.HELPERS, args) def dependencies(self): return [ClassNode(self.gen, self.HELPERS)] Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 14:29:22 2006 @@ -1,8 +1,6 @@ -import sys -from pypy.objspace.flow.model import Constant, Variable from pypy.rpython.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong -from pypy.rpython.ootypesystem.ootype import Instance -from pypy.translator.squeak.message import Message, camel_case +from pypy.translator.squeak.codeformatter import CodeFormatter +from pypy.translator.squeak.codeformatter import Message, Self, Assignment, Field def _setup_int_masks(): """Generates code for helpers to mask the various integer types.""" @@ -57,20 +55,7 @@ def __init__(self, gen, node): self.gen = gen self.node = node - - def expr(self, v): - # XXX this code duplicated in gensqueak.py - if isinstance(v, Variable): - return camel_case(v.name) - elif isinstance(v, Constant): - if isinstance(v.concretetype, Instance): - const_id = self.gen.unique_name( - v, "const_%s" % self.gen.nameof(v.value._TYPE)) - self.gen.constant_insts[v] = const_id - return "(PyConstants getConstant: '%s')" % const_id - return self.gen.nameof(v.value) - else: - raise TypeError, "expr(%r)" % (v,) + self.codef = CodeFormatter(gen) def format(self, op): opname_parts = op.opname.split("_") @@ -81,84 +66,72 @@ if op_method is not None: return op_method(op) else: - name = op.opname - name = self.ops.get(name, name) - receiver = self.expr(op.args[0]) - args = [self.expr(arg) for arg in op.args[1:]] - return self.assignment(op, receiver, name, args) + name = self.ops.get(op.opname, op.opname) + sent = Message(name).send_to(op.args[0], op.args[1:]) + return self.codef.format(sent.assign_to(op.result)) def format_number_op(self, op, ptype, opname): - receiver = self.expr(op.args[0]) - args = [self.expr(arg) for arg in op.args[1:]] - sel = Message(self.number_ops[opname]) - message = "%s %s" % (receiver, sel.signature(args)) + message = Message(self.number_ops[opname]) + sent_message = message.send_to(op.args[0], op.args[1:]) if opname in self.wrapping_ops \ and self.int_masks.has_key(ptype): from pypy.translator.squeak.gensqueak import HelperNode mask_name, mask_code = self.int_masks[ptype] helper = HelperNode(self.gen, Message(mask_name), mask_code) - message = helper.apply(["(%s)" % message]) + sent_message = helper.apply([sent_message]) self.gen.schedule_node(helper) - return "%s := %s." % (self.expr(op.result), message) - - def assignment(self, op, receiver_name, sel_name, arg_names): - sel = Message(sel_name) - return "%s := %s %s." % (self.expr(op.result), - receiver_name, sel.signature(arg_names)) + return self.codef.format(sent_message.assign_to(op.result)) def op_oosend(self, op): - message = op.args[0].value + message_name = op.args[0].value if op.args[1] == self.node.self: - receiver = "self" + receiver = Self() else: - receiver = self.expr(op.args[1]) - args = [self.expr(a) for a in op.args[2:]] + receiver = op.args[1] from pypy.translator.squeak.gensqueak import MethodNode self.gen.schedule_node( - MethodNode(self.gen, op.args[1].concretetype, message)) - return self.assignment(op, receiver, message, args) + MethodNode(self.gen, op.args[1].concretetype, message_name)) + sent_message = Message(message_name).send_to(receiver, op.args[2:]) + return self.codef.format(sent_message.assign_to(op.result)) def op_oogetfield(self, op): INST = op.args[0].concretetype - receiver = self.expr(op.args[0]) field_name = self.node.unique_field(INST, op.args[1].value) if op.args[0] == self.node.self: # Private field access # Could also directly substitute op.result with name # everywhere for optimization. - return "%s := %s." % (self.expr(op.result), field_name) + rvalue = Field(field_name) else: # Public field access from pypy.translator.squeak.gensqueak import GetterNode self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) - return self.assignment(op, receiver, field_name, []) + rvalue = Message(field_name).send_to(op.args[0], []) + return self.codef.format(Assignment(op.result, rvalue)) def op_oosetfield(self, op): # Note that the result variable is never used INST = op.args[0].concretetype field_name = self.node.unique_field(INST, op.args[1].value) - field_value = self.expr(op.args[2]) + field_value = op.args[2] if op.args[0] == self.node.self: # Private field access - return "%s := %s." % (field_name, field_value) + return self.codef.format(Assignment(Field(field_name), field_value)) else: # Public field access from pypy.translator.squeak.gensqueak import SetterNode self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) - receiver = self.expr(op.args[0]) - return "%s %s: %s." % (receiver, field_name, field_value) + setter = Message(field_name).send_to(op.args[0], [field_value]) + return self.codef.format(setter) def op_oodowncast(self, op): - return "%s := %s." % (self.expr(op.result), self.expr(op.args[0])) + return self.codef.format(Assignment(op.result, op.args[0])) def op_direct_call(self, op): - # XXX not sure if static methods of a specific class should - # be treated differently. from pypy.translator.squeak.gensqueak import FunctionNode - receiver = "PyFunctions" - callable_name = self.expr(op.args[0]) - args = [self.expr(a) for a in op.args[1:]] + function_name = self.node.expr(op.args[0]) self.gen.schedule_node( FunctionNode(self.gen, op.args[0].value.graph)) - return self.assignment(op, receiver, callable_name, args) + msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) + return self.codef.format(msg.assign_to(op.result)) Added: pypy/dist/pypy/translator/squeak/test/test_codeformatter.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/test_codeformatter.py Thu Mar 16 14:29:22 2006 @@ -0,0 +1,41 @@ +from pypy.objspace.flow.model import Constant +from pypy.rpython.ootypesystem.ootype import Signed, Bool, Void +from pypy.translator.squeak.codeformatter import CodeFormatter +from pypy.translator.squeak.codeformatter import Message + +C = Constant + +def test_messagewithargs(): + c = CodeFormatter() + m = Message("bla") + assert c.format(m.with_args([])) == "bla" + assert c.format(m.with_args([C(1, Signed), C(2, Signed)])) \ + == "bla: 1 with: 2" + m = Message("+") + assert c.format(m.with_args([C(1, Signed)])) == "+ 1" + +def test_sentmessage(): + c = CodeFormatter() + receiver = C(100, Signed) + args = [C(1, Signed), C(2, Signed)] + m = Message("bla").send_to(receiver, args) + assert c.format(m) == "(100 bla: 1 with: 2)" + m = Message("bla").with_args(args).send_to(receiver) + assert c.format(m) == "(100 bla: 1 with: 2)" + +def test_assignment(): + c = CodeFormatter() + result = C(200, Signed) + receiver = C(100, Signed) + args = [C(1, Signed), C(2, Signed)] + m = Message("bla").send_to(receiver, args).assign_to(result) + assert c.format(m) == "200 := (100 bla: 1 with: 2)" + +def test_argformatting(): + c = CodeFormatter() + m = Message("b") + bools = [C(True, Bool), C(False, Bool)] + null = C(None, Void) + assert c.format(m.with_args(bools)) == "b: true with: false" + assert c.format(m.with_args([null])) == "b: nil" + From nik at codespeak.net Thu Mar 16 14:42:28 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 14:42:28 +0100 (CET) Subject: [pypy-svn] r24465 - pypy/dist/pypy/translator/squeak Message-ID: <20060316134228.8709810092@code0.codespeak.net> Author: nik Date: Thu Mar 16 14:42:27 2006 New Revision: 24465 Added: pypy/dist/pypy/translator/squeak/node.py Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/opformatter.py Log: move node classes into their own module. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 14:42:27 2006 @@ -1,11 +1,7 @@ -import datetime, sys -from pypy.objspace.flow.model import Constant, Variable, Block -from pypy.objspace.flow.model import last_exception, checkgraph +from pypy.objspace.flow.model import Constant from pypy.translator.gensupp import NameManager from pypy.translator.squeak.message import Message, camel_case -from pypy.translator.squeak.opformatter import OpFormatter -from pypy.rpython.ootypesystem.ootype import Instance, ROOT -from pypy import conftest +from pypy.translator.squeak.node import FunctionNode, ClassNode, SetupNode try: set except NameError: @@ -32,9 +28,6 @@ self.generated_nodes = set() self.constant_insts = {} - if conftest.option.view: - self.translator.view() - graph = self.translator.graphs[0] self.pending_nodes.append(FunctionNode(self, graph)) self.filename = '%s.st' % graph.name @@ -120,321 +113,3 @@ return unique -class CodeNode: - - def __hash__(self): - return hash(self.hash_key) - - def __eq__(self, other): - return isinstance(other, CodeNode) \ - and self.hash_key == other.hash_key - - # XXX need other comparison methods? - - def render_fileout_header(self, class_name, category): - return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( - class_name, category, - datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) - - def unique_field(self, INSTANCE, field_name): - # XXX for now we ignore the issue of nameclashes between - # field names. It's not so simple because superclasses must - # be considered, too. - return camel_case(field_name) - -class ClassNode(CodeNode): - - def __init__(self, gen, INSTANCE, class_vars=None): - self.gen = gen - self.INSTANCE = INSTANCE - self.class_vars = [] # XXX should probably go away - if class_vars is not None: - self.class_vars = class_vars - self.hash_key = INSTANCE - - def dependencies(self): - if self.INSTANCE._superclass is not None: # not root - return [ClassNode(self.gen, self.INSTANCE._superclass)] - else: - return [] - - def render(self): - yield "%s subclass: #%s" % ( - self.gen.nameof_Instance(self.INSTANCE._superclass), - self.gen.nameof_Instance(self.INSTANCE)) - fields = [self.unique_field(self.INSTANCE, f) for f in - self.INSTANCE._fields.iterkeys()] - yield " instanceVariableNames: '%s'" % ' '.join(fields) - yield " classVariableNames: '%s'" % ' '.join(self.class_vars) - yield " poolDictionaries: ''" - yield " category: 'PyPy-Test'!" - -class LoopFinder: - - def __init__(self, startblock): - self.loops = {} - self.parents = {startblock: startblock} - self.temps = {} - self.seen = [] - self.visit_Block(startblock) - - def visit_Block(self, block, switches=[]): - #self.temps.has_key() - self.seen.append(block) - if block.exitswitch: - switches.append(block) - self.parents[block] = block - for link in block.exits: - self.visit_Link(link, switches) - - def visit_Link(self, link, switches): - if link.target in switches: - self.loops[link.target] = True - if not link.target in self.seen: - self.parents[link.target] = self.parents[link.prevblock] - self.visit_Block(link.target, switches) - -class CallableNode(CodeNode): - - def render_body(self, startblock): - self.loops = LoopFinder(startblock).loops - args = self.arguments(startblock) - sel = Message(self.name) - yield sel.signature([self.expr(v) for v in args]) - - # XXX should declare local variables here - for line in self.render_block(startblock): - yield " %s" % line - yield '! !' - - def expr(self, v): - if isinstance(v, Variable): - return camel_case(v.name) - elif isinstance(v, Constant): - if isinstance(v.concretetype, Instance): - const_id = self.gen.unique_name( - v, "const_%s" % self.gen.nameof(v.value._TYPE)) - self.gen.constant_insts[v] = const_id - return "(PyConstants getConstant: '%s')" % const_id - return self.gen.nameof(v.value) - else: - raise TypeError, "expr(%r)" % (v,) - - def render_return(self, args): - if len(args) == 2: - # exception - exc_cls = self.expr(args[0]) - exc_val = self.expr(args[1]) - yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) - else: - # regular return block - retval = self.expr(args[0]) - yield "^%s" % retval - - def render_link(self, link): - block = link.target - if link.args: - for i in range(len(link.args)): - yield '%s := %s.' % \ - (self.expr(block.inputargs[i]), self.expr(link.args[i])) - for line in self.render_block(block): - yield line - - def render_block(self, block): - if self.loops.has_key(block): - if not self.loops[block]: - yield '"skip1"' - return - yield "[" - formatter = OpFormatter(self.gen, self) - for op in block.operations: - yield "%s." % formatter.format(op) - if len(block.exits) == 0: - for line in self.render_return(block.inputargs): - yield line - return - elif block.exitswitch is None: - # single-exit block - assert len(block.exits) == 1 - for line in self.render_link(block.exits[0]): - yield line - else: - #exitswitch - if self.loops.has_key(block): - if self.loops[block]: - self.loops[block] = False - yield "%s] whileTrue: [" % self.expr(block.exitswitch) - for line in self.render_link(block.exits[True]): - yield " %s" % line - yield "]." - for line in self.render_link(block.exits[False]): - yield "%s" % line - else: - yield "%s ifTrue: [" % self.expr(block.exitswitch) - for line in self.render_link(block.exits[True]): - yield " %s" % line - yield "] ifFalse: [" - for line in self.render_link(block.exits[False]): - yield " %s" % line - yield "]" - -class MethodNode(CallableNode): - - def __init__(self, gen, INSTANCE, method_name): - self.gen = gen - self.INSTANCE = INSTANCE - self.name = method_name - self.self = None # Will be set upon rendering - self.hash_key = (INSTANCE, method_name) - - def dependencies(self): - return [ClassNode(self.gen, self.INSTANCE)] - - def arguments(self, startblock): - # Omit the explicit self - return startblock.inputargs[1:] - - def render(self): - yield self.render_fileout_header( - self.gen.nameof(self.INSTANCE), "methods") - graph = self.INSTANCE._methods[self.name].graph - self.self = graph.startblock.inputargs[0] - for line in self.render_body(graph.startblock): - yield line - -class FunctionNode(CallableNode): - - FUNCTIONS = Instance("Functions", ROOT) - - def __init__(self, gen, graph): - self.gen = gen - self.graph = graph - self.name = gen.nameof(graph.func) - self.self = None - self.hash_key = graph - - def dependencies(self): - return [ClassNode(self.gen, self.FUNCTIONS)] - - def arguments(self, startblock): - return startblock.inputargs - - def render(self): - yield self.render_fileout_header("PyFunctions class", "functions") - for line in self.render_body(self.graph.startblock): - yield line - -class AccessorNode(CodeNode): - - def __init__(self, gen, INSTANCE, field_name): - self.gen = gen - self.INSTANCE = INSTANCE - self.field_name = field_name - self.hash_key = (INSTANCE, field_name, self.__class__) - - def dependencies(self): - return [ClassNode(self.gen, self.INSTANCE)] - -class SetterNode(AccessorNode): - - def render(self): - yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "accessors") - yield "%s: value" % self.field_name - yield " %s := value" % self.field_name - yield "! !" - -class GetterNode(AccessorNode): - - def render(self): - yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "accessors") - yield self.field_name - yield " ^%s" % self.field_name - yield "! !" - -class HelperNode(CodeNode): - - HELPERS = Instance("Helpers", ROOT) - - def __init__(self, gen, message, code): - self.gen = gen - self.message = message - self.code = code - self.hash_key = ("helper", code) - - def apply(self, args): - return self.message.send_to(self.HELPERS, args) - - def dependencies(self): - return [ClassNode(self.gen, self.HELPERS)] - - def render(self): - # XXX should not use explicit name "PyHelpers" here - yield self.render_fileout_header("PyHelpers class", "helpers") - for line in self.code.strip().split("\n"): - yield line - yield "! !" - -class FieldInitializerNode(CodeNode): - - def __init__(self, gen, INSTANCE): - self.gen = gen - self.INSTANCE = INSTANCE - self.hash_key = ("fieldinit", INSTANCE) - - def dependencies(self): - return [ClassNode(self.gen, self.INSTANCE)] - - def render(self): - yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "initializers") - fields = self.INSTANCE._allfields() - sel = Message("field_init") - arg_names = ["a%s" % i for i in range(len(fields))] - yield sel.signature(arg_names) - for field_name, arg_name in zip(fields.keys(), arg_names): - yield " %s := %s." % ( - self.unique_field(self.INSTANCE, field_name), - arg_name) - yield "! !" - -class SetupNode(CodeNode): - - CONSTANTS = Instance("Constants", ROOT) - - def __init__(self, gen, constants): - self.gen = gen - self.constants = constants - self.hash_key = "setup" - - def dependencies(self): - # Important: Field initializers for the *runtime* type - return [FieldInitializerNode(self.gen, c.value._TYPE) - for c in self.constants.iterkeys()] + \ - [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] - - def render(self): - yield self.render_fileout_header("PyConstants class", "internals") - sel = Message("setupConstants") - yield sel.signature([]) - yield " Constants := Dictionary new." - for const, const_id in self.constants.iteritems(): - INST = const.value._TYPE - class_name = self.gen.nameof(INST) - field_names = INST._allfields().keys() - field_values = [self.gen.nameof(getattr(const.value, f)) - for f in field_names] - init_sel = Message("field_init") - yield " Constants at: '%s' put: (%s new %s)." \ - % (const_id, class_name, - init_sel.signature(field_values)) - yield "! !" - yield "" - - yield self.render_fileout_header("PyConstants class", "internals") - sel = Message("getConstant") - yield sel.signature(["constId"]) - yield " ^ Constants at: constId" - yield "! !" - Added: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/node.py Thu Mar 16 14:42:27 2006 @@ -0,0 +1,324 @@ +import datetime +from pypy.objspace.flow.model import Constant, Variable +from pypy.translator.squeak.message import Message, camel_case +from pypy.translator.squeak.opformatter import OpFormatter +from pypy.rpython.ootypesystem.ootype import Instance, ROOT + +class CodeNode: + + def __hash__(self): + return hash(self.hash_key) + + def __eq__(self, other): + return isinstance(other, CodeNode) \ + and self.hash_key == other.hash_key + + # XXX need other comparison methods? + + def render_fileout_header(self, class_name, category): + return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( + class_name, category, + datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) + + def unique_field(self, INSTANCE, field_name): + # XXX for now we ignore the issue of nameclashes between + # field names. It's not so simple because superclasses must + # be considered, too. + return camel_case(field_name) + +class ClassNode(CodeNode): + + def __init__(self, gen, INSTANCE, class_vars=None): + self.gen = gen + self.INSTANCE = INSTANCE + self.class_vars = [] # XXX should probably go away + if class_vars is not None: + self.class_vars = class_vars + self.hash_key = INSTANCE + + def dependencies(self): + if self.INSTANCE._superclass is not None: # not root + return [ClassNode(self.gen, self.INSTANCE._superclass)] + else: + return [] + + def render(self): + yield "%s subclass: #%s" % ( + self.gen.nameof_Instance(self.INSTANCE._superclass), + self.gen.nameof_Instance(self.INSTANCE)) + fields = [self.unique_field(self.INSTANCE, f) for f in + self.INSTANCE._fields.iterkeys()] + yield " instanceVariableNames: '%s'" % ' '.join(fields) + yield " classVariableNames: '%s'" % ' '.join(self.class_vars) + yield " poolDictionaries: ''" + yield " category: 'PyPy-Test'!" + +class LoopFinder: + + def __init__(self, startblock): + self.loops = {} + self.parents = {startblock: startblock} + self.temps = {} + self.seen = [] + self.visit_Block(startblock) + + def visit_Block(self, block, switches=[]): + #self.temps.has_key() + self.seen.append(block) + if block.exitswitch: + switches.append(block) + self.parents[block] = block + for link in block.exits: + self.visit_Link(link, switches) + + def visit_Link(self, link, switches): + if link.target in switches: + self.loops[link.target] = True + if not link.target in self.seen: + self.parents[link.target] = self.parents[link.prevblock] + self.visit_Block(link.target, switches) + +class CallableNode(CodeNode): + + def render_body(self, startblock): + self.loops = LoopFinder(startblock).loops + args = self.arguments(startblock) + sel = Message(self.name) + yield sel.signature([self.expr(v) for v in args]) + + # XXX should declare local variables here + for line in self.render_block(startblock): + yield " %s" % line + yield '! !' + + def expr(self, v): + if isinstance(v, Variable): + return camel_case(v.name) + elif isinstance(v, Constant): + if isinstance(v.concretetype, Instance): + const_id = self.gen.unique_name( + v, "const_%s" % self.gen.nameof(v.value._TYPE)) + self.gen.constant_insts[v] = const_id + return "(PyConstants getConstant: '%s')" % const_id + return self.gen.nameof(v.value) + else: + raise TypeError, "expr(%r)" % (v,) + + def render_return(self, args): + if len(args) == 2: + # exception + exc_cls = self.expr(args[0]) + exc_val = self.expr(args[1]) + yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) + else: + # regular return block + retval = self.expr(args[0]) + yield "^%s" % retval + + def render_link(self, link): + block = link.target + if link.args: + for i in range(len(link.args)): + yield '%s := %s.' % \ + (self.expr(block.inputargs[i]), self.expr(link.args[i])) + for line in self.render_block(block): + yield line + + def render_block(self, block): + if self.loops.has_key(block): + if not self.loops[block]: + yield '"skip1"' + return + yield "[" + formatter = OpFormatter(self.gen, self) + for op in block.operations: + yield "%s." % formatter.format(op) + if len(block.exits) == 0: + for line in self.render_return(block.inputargs): + yield line + return + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for line in self.render_link(block.exits[0]): + yield line + else: + #exitswitch + if self.loops.has_key(block): + if self.loops[block]: + self.loops[block] = False + yield "%s] whileTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "]." + for line in self.render_link(block.exits[False]): + yield "%s" % line + else: + yield "%s ifTrue: [" % self.expr(block.exitswitch) + for line in self.render_link(block.exits[True]): + yield " %s" % line + yield "] ifFalse: [" + for line in self.render_link(block.exits[False]): + yield " %s" % line + yield "]" + +class MethodNode(CallableNode): + + def __init__(self, gen, INSTANCE, method_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.name = method_name + self.self = None # Will be set upon rendering + self.hash_key = (INSTANCE, method_name) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def arguments(self, startblock): + # Omit the explicit self + return startblock.inputargs[1:] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof(self.INSTANCE), "methods") + graph = self.INSTANCE._methods[self.name].graph + self.self = graph.startblock.inputargs[0] + for line in self.render_body(graph.startblock): + yield line + +class FunctionNode(CallableNode): + + FUNCTIONS = Instance("Functions", ROOT) + + def __init__(self, gen, graph): + self.gen = gen + self.graph = graph + self.name = gen.nameof(graph.func) + self.self = None + self.hash_key = graph + + def dependencies(self): + return [ClassNode(self.gen, self.FUNCTIONS)] + + def arguments(self, startblock): + return startblock.inputargs + + def render(self): + yield self.render_fileout_header("PyFunctions class", "functions") + for line in self.render_body(self.graph.startblock): + yield line + +class AccessorNode(CodeNode): + + def __init__(self, gen, INSTANCE, field_name): + self.gen = gen + self.INSTANCE = INSTANCE + self.field_name = field_name + self.hash_key = (INSTANCE, field_name, self.__class__) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + +class SetterNode(AccessorNode): + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield "%s: value" % self.field_name + yield " %s := value" % self.field_name + yield "! !" + +class GetterNode(AccessorNode): + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "accessors") + yield self.field_name + yield " ^%s" % self.field_name + yield "! !" + +class HelperNode(CodeNode): + + HELPERS = Instance("Helpers", ROOT) + + def __init__(self, gen, message, code): + self.gen = gen + self.message = message + self.code = code + self.hash_key = ("helper", code) + + def apply(self, args): + return self.message.send_to(self.HELPERS, args) + + def dependencies(self): + return [ClassNode(self.gen, self.HELPERS)] + + def render(self): + # XXX should not use explicit name "PyHelpers" here + yield self.render_fileout_header("PyHelpers class", "helpers") + for line in self.code.strip().split("\n"): + yield line + yield "! !" + +class FieldInitializerNode(CodeNode): + + def __init__(self, gen, INSTANCE): + self.gen = gen + self.INSTANCE = INSTANCE + self.hash_key = ("fieldinit", INSTANCE) + + def dependencies(self): + return [ClassNode(self.gen, self.INSTANCE)] + + def render(self): + yield self.render_fileout_header( + self.gen.nameof_Instance(self.INSTANCE), "initializers") + fields = self.INSTANCE._allfields() + sel = Message("field_init") + arg_names = ["a%s" % i for i in range(len(fields))] + yield sel.signature(arg_names) + for field_name, arg_name in zip(fields.keys(), arg_names): + yield " %s := %s." % ( + self.unique_field(self.INSTANCE, field_name), + arg_name) + yield "! !" + +class SetupNode(CodeNode): + + CONSTANTS = Instance("Constants", ROOT) + + def __init__(self, gen, constants): + self.gen = gen + self.constants = constants + self.hash_key = "setup" + + def dependencies(self): + # Important: Field initializers for the *runtime* type + return [FieldInitializerNode(self.gen, c.value._TYPE) + for c in self.constants.iterkeys()] + \ + [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] + + def render(self): + yield self.render_fileout_header("PyConstants class", "internals") + sel = Message("setupConstants") + yield sel.signature([]) + yield " Constants := Dictionary new." + for const, const_id in self.constants.iteritems(): + INST = const.value._TYPE + class_name = self.gen.nameof(INST) + field_names = INST._allfields().keys() + field_values = [self.gen.nameof(getattr(const.value, f)) + for f in field_names] + init_sel = Message("field_init") + yield " Constants at: '%s' put: (%s new %s)." \ + % (const_id, class_name, + init_sel.signature(field_values)) + yield "! !" + yield "" + + yield self.render_fileout_header("PyConstants class", "internals") + sel = Message("getConstant") + yield sel.signature(["constId"]) + yield " ^ Constants at: constId" + yield "! !" + Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 14:42:27 2006 @@ -75,7 +75,7 @@ sent_message = message.send_to(op.args[0], op.args[1:]) if opname in self.wrapping_ops \ and self.int_masks.has_key(ptype): - from pypy.translator.squeak.gensqueak import HelperNode + from pypy.translator.squeak.node import HelperNode mask_name, mask_code = self.int_masks[ptype] helper = HelperNode(self.gen, Message(mask_name), mask_code) sent_message = helper.apply([sent_message]) @@ -88,7 +88,7 @@ receiver = Self() else: receiver = op.args[1] - from pypy.translator.squeak.gensqueak import MethodNode + from pypy.translator.squeak.node import MethodNode self.gen.schedule_node( MethodNode(self.gen, op.args[1].concretetype, message_name)) sent_message = Message(message_name).send_to(receiver, op.args[2:]) @@ -104,7 +104,7 @@ rvalue = Field(field_name) else: # Public field access - from pypy.translator.squeak.gensqueak import GetterNode + from pypy.translator.squeak.node import GetterNode self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) rvalue = Message(field_name).send_to(op.args[0], []) return self.codef.format(Assignment(op.result, rvalue)) @@ -119,7 +119,7 @@ return self.codef.format(Assignment(Field(field_name), field_value)) else: # Public field access - from pypy.translator.squeak.gensqueak import SetterNode + from pypy.translator.squeak.node import SetterNode self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) setter = Message(field_name).send_to(op.args[0], [field_value]) return self.codef.format(setter) @@ -128,7 +128,7 @@ return self.codef.format(Assignment(op.result, op.args[0])) def op_direct_call(self, op): - from pypy.translator.squeak.gensqueak import FunctionNode + from pypy.translator.squeak.node import FunctionNode function_name = self.node.expr(op.args[0]) self.gen.schedule_node( FunctionNode(self.gen, op.args[0].value.graph)) From cfbolz at codespeak.net Thu Mar 16 15:02:23 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 15:02:23 +0100 (CET) Subject: [pypy-svn] r24466 - in pypy/dist/pypy/rpython/memory: . test Message-ID: <20060316140223.B8B55100A7@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 15:02:22 2006 New Revision: 24466 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: fix the quite broken gc_(un)protect code: * raise NotImplementedError in the base class, since (un)protect does not make sense for most gcs * make sure that the new operation introduced by replace_gc_(un)protect has the same result variable as the replaced operation. Otherwise we will end up with graphs that are missing a variable. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Thu Mar 16 15:02:22 2006 @@ -216,12 +216,14 @@ return [SpaceOperation("gc_pop_alive_pyobj", [var], result)] def replace_gc_protect(self, op, livevars): - """ protect this object from gc (make it immortal) """ - return [], [] + """ protect this object from gc (make it immortal). the specific + gctransformer needs to overwrite this""" + raise NotImplementedError("gc_protect does not make sense for this gc") def replace_gc_unprotect(self, op, livevars): - """ get this object back into gc control """ - return [], [] + """ get this object back into gc control. the specific gctransformer + needs to overwrite this""" + raise NotImplementedError("gc_protect does not make sense for this gc") def annotate_helper(self, ll_helper, ll_args, ll_result): assert not self.finished @@ -367,11 +369,15 @@ def replace_gc_protect(self, op, livevars): """ protect this object from gc (make it immortal) """ - return self.push_alive(op.args[0]), [] + newops = self.push_alive(op.args[0]) + newops[-1].result = op.result + return newops, [] def replace_gc_unprotect(self, op, livevars): """ get this object back into gc control """ - return self.pop_alive(op.args[0]), [] + newops = self.pop_alive(op.args[0]) + newops[-1].result = op.result + return newops, [] def replace_setfield(self, op, livevars): if not var_needsgc(op.args[2]): @@ -583,6 +589,14 @@ def pop_alive_nopyobj(self, var): return [] + def replace_gc_protect(self, op, livevars): + """ for boehm it is enough to do nothing""" + return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] + + def replace_gc_unprotect(self, op, livevars): + """ for boehm it is enough to do nothing""" + return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] + def get_rtti(self, TYPE): if isinstance(TYPE, lltype.GcStruct): try: Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Thu Mar 16 15:02:22 2006 @@ -231,8 +231,8 @@ extregistry.register_value(unprotect, compute_result_annotation=annmodel.s_None, specialize_call=rtype_unprotect) - def p(): protect('this is an object') - def u(): unprotect('this is an object') + def p(): return protect('this is an object') + def u(): return unprotect('this is an object') rgc = gctransform.RefcountingGCTransformer bgc = gctransform.BoehmGCTransformer From ac at codespeak.net Thu Mar 16 15:35:37 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Mar 2006 15:35:37 +0100 (CET) Subject: [pypy-svn] r24469 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060316143537.90AC8100A3@code0.codespeak.net> Author: ac Date: Thu Mar 16 15:35:36 2006 New Revision: 24469 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: Atleast me and Samuele are comming from Strakt. Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Thu Mar 16 15:35:36 2006 @@ -11,9 +11,9 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== -Anders Chrigstroem ? Ermina? +Anders Chrigstroem 2/3 - 10/3 Ermina Holger Krekel ? Ermina? -Samuele Pedroni ? Ermina? +Samuele Pedroni 2/3 - 10/3 Ermina Armin Rigo -- private Christian Tismer ? Ermina? Michael Hudson 3rd-10th? Ermina? From ac at codespeak.net Thu Mar 16 16:04:12 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Mar 2006 16:04:12 +0100 (CET) Subject: [pypy-svn] r24473 - in pypy/dist/pypy: interpreter module/stackless Message-ID: <20060316150412.3FF45100A6@code0.codespeak.net> Author: ac Date: Thu Mar 16 16:04:11 2006 New Revision: 24473 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/module/stackless/coroutine.py Log: (pedronis, arre) Make a single point of creation for framestacks. Fixed subcontext_switch. Don't store initially a framestack in AppCoroutine for the main coroutine. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 16 16:04:11 2006 @@ -2,13 +2,16 @@ from pypy.interpreter.miscutils import Stack from pypy.interpreter.error import OperationError +def new_framestack(): + return Stack() + class ExecutionContext: """An ExecutionContext holds the state of an execution thread in the Python interpreter.""" def __init__(self, space): self.space = space - self.framestack = Stack() + self.framestack = new_framestack() self.w_tracefunc = None self.w_profilefunc = None self.is_tracing = 0 @@ -36,17 +39,23 @@ # coroutine: subcontext support def subcontext_new(coobj): - coobj.framestack = Stack() + coobj.framestack = new_framestack() coobj.w_tracefunc = None coobj.w_profilefunc = None coobj.is_tracing = 0 subcontext_new = staticmethod(subcontext_new) - def subcontext_swap(self, coobj): - self.framestack, coobj.framestack = coobj.framestack, self.framestack - self.w_tracefunc, coobj.w_tracefunc = coobj.w_tracefunc, self.w_tracefunc - self.w_profilefunc, coobj.w_profilefunc = coobj.w_profilefunc, self.w_profilefunc - self.is_tracing, coobj.is_tracing = coobj.is_tracing, self.is_tracing + def subcontext_switch(self, current, next): + current.framestack = self.framestack + current.w_tracefunc = self.w_tracefunc + current.w_profilefunc = self.w_profilefunc + current.is_tracing = self.is_tracing + + self.framestack = next.framestack + self.w_tracefunc = next.w_tracefunc + self.w_profilefunc = next.w_profilefunc + self.is_tracing = next.is_tracing + # coroutine: I think this is all, folks! def get_builtin(self): Modified: pypy/dist/pypy/module/stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/stackless/coroutine.py (original) +++ pypy/dist/pypy/module/stackless/coroutine.py Thu Mar 16 16:04:11 2006 @@ -45,12 +45,13 @@ class AppCoroutine(Coroutine): # XXX, StacklessFlags): - def __init__(self, space): + def __init__(self, space, is_main=False): self.space = space state = self._get_state(space) Coroutine.__init__(self, state) self.flags = 0 - space.getexecutioncontext().subcontext_new(self) + if not is_main: + space.getexecutioncontext().subcontext_new(self) def descr_method__new__(space, w_subtype): co = space.allocate_instance(AppCoroutine, w_subtype) @@ -143,4 +144,4 @@ self.space = space def post_install(self): - self.current = self.main = self.last = AppCoroutine(self.space) + self.current = self.main = self.last = AppCoroutine(self.space, is_main=True) From auc at codespeak.net Thu Mar 16 16:35:31 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 16 Mar 2006 16:35:31 +0100 (CET) Subject: [pypy-svn] r24479 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060316153531.2F3D1100AB@code0.codespeak.net> Author: auc Date: Thu Mar 16 16:35:28 2006 New Revision: 24479 Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/constraint.py pypy/dist/pypy/lib/logic/computation_space/problems.py pypy/dist/pypy/lib/logic/computation_space/solvers.py pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Log: cleanup, soon alldistinct Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Thu Mar 16 16:35:28 2006 @@ -10,21 +10,8 @@ from distributor import DefaultDistributor import event # NewSpace, Clone, Revise -class Succeeded: pass -class Failed(Exception): pass - -class Alternative(object): - - def __init__(self, choices): - self._choices = choices - - def __eq__(self, other): - if other is None: return False - if not isinstance(other, Alternative): return False - return self._choices == other._choices - - def __str__(self): - return "Alternatives(%s)" % self._choices +Failed = 0 +Succeeded = 1 def NoProblem(): """the empty problem, used by clone()""" @@ -100,6 +87,9 @@ ret.append(">") return ' '.join(ret) + def __repr__(self): + return "" % self.id + def __eq__(self, spc): """space equality defined as : * identity, or @@ -151,7 +141,6 @@ res = False return res - #-- Computation Space ----------------------------------------- #-- space helpers ----------------------------------------- @@ -184,7 +173,7 @@ if self.status in (Failed, Succeeded): return self.status if self._distributable(): - return Alternative(self.distributor.nb_subdomains()) + return self.distributor.nb_subdomains() def clone(self): spc = ComputationSpace(NoProblem, parent=self) @@ -263,7 +252,7 @@ self.names[name] = var print "just created new var %s" % var - def get_var_by_name(self, name): + def find_var(self, name): """looks up one variable""" try: return self.names[name] @@ -279,12 +268,12 @@ raise NotInStore(str(names)) def is_bound(self, var): - """check wether a var is locally bound""" + """check wether a var has a singleton domain""" return len(self.dom(var)) == 1 def val(self, var): - """return the local binding without blocking""" - if self.is_bound(var): # the speculative val + """return the speculative""" + if self.is_bound(var): return self.dom(var)[0] return NoValue @@ -347,9 +336,6 @@ #-- Constraint propagation --------------- - def add_distributed(self, var): - self.changelog.append(var) - def _init_constraint_queue(self): cqueue = [] init_const_set = set() @@ -365,7 +351,7 @@ return cqueue def satisfy_all(self): - """really PROPAGATE""" + """really PROPAGATE from AC3""" const_q = self._init_constraint_queue() assert const_q != [] const_q.sort() @@ -379,7 +365,7 @@ const_q.sort() affected_constraints.clear() cost, const = const_q.pop(0) - entailed = const.revise3() + entailed = const.revise() for var in const.affected_variables(): dom = self.dom(var) if not dom.has_changed(): Modified: pypy/dist/pypy/lib/logic/computation_space/constraint.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/constraint.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/constraint.py Thu Mar 16 16:35:28 2006 @@ -51,14 +51,12 @@ def remove_value(self, value): """Remove value of domain and check for consistency""" -## print "removing", value, "from", self._values.keys() - del self._values[value] + self._values.remove(value) self._value_removed() def remove_values(self, values): """Remove values of domain and check for consistency""" if values: -## print "removing", values, "from", self._values.keys() for val in values : self._values.remove(val) self._value_removed() @@ -159,7 +157,7 @@ def getVariable(self): return self._variable - def revise3(self, domains): + def revise(self, domains): domain = domains[self._variable] operator = self._operator ref = self._reference @@ -184,6 +182,72 @@ expr.replace(var.name, var.name + '.val') return expr + +class AllDistinct(AbstractConstraint): + """Contraint: all values must be distinct""" + + def __init__(self, c_space, variables): + assert len(variables)>1 + AbstractConstraint.__init__(self, c_space, variables) + # worst case complexity + self.__cost = len(variables) * (len(variables) - 1) / 2 + + def __repr__(self): + return '' % str(self._variables) + + def copy_to(self, space): + return self.__class__(space, self._variables) + + def estimateCost(self, domains): + return self.__cost + + def test_solution(self, sol): + """test a solution against this constraint + accept a mapping of variable names to value""" + values = sol.items() + value_set = set(values) + return len(value_set) == len(sol) + + def revise(self): + variables = [(self.cs.dom(variable).size(), + variable, self.cs.dom(variable)) + for variable in self._variables] + + variables.sort() + # if a domain has a size of 1, + # then the value must be removed from the other domains + for size, var, dom in variables: + if dom.size() == 1: + print "AllDistinct removes values" + for _siz, _var, _dom in variables: + if _var != var: + try: + _dom.remove_value(dom.get_values()[0]) + except KeyError: + # we ignore errors caused by the removal of + # non existing values + pass + + # if there are less values than variables, the constraint fails + values = {} + for size, var, dom in variables: + for val in dom: + values[val] = 0 + if len(values) < len(variables): + print "AllDistinct failed" + raise ConsistencyFailure() + + # the constraint is entailed if all domains have a size of 1 + for variable in variables: + if variable[2].size() != 1: + return 0 + + # Question : did we *really* completely check + # our own alldistinctness predicate ? + + return 1 + + class Expression(AbstractConstraint): """A constraint represented as a python expression.""" _FILTER_CACHE = {} @@ -202,7 +266,7 @@ Expression._FILTER_CACHE[formula] = self.filterFunc def test_solution(self, sol ): - """FOR TESTING: test a solution against this constraint + """test a solution against this constraint accept a mapping of variable names to value""" args = [] for var in self._variables: @@ -249,7 +313,7 @@ # it's over go_on = 0 - def revise3(self): + def revise(self): # removed domain arg. (auc, ale) """generic propagation algorithm for n-ary expressions""" maybe_entailed = 1 @@ -305,7 +369,7 @@ def copy_to(self, space): raise NotImplementedError - def revise3(self, domains): + def revise(self, domains): """specialized narrowing algorithm for binary expressions Runs much faster than the generic version""" maybe_entailed = 1 Modified: pypy/dist/pypy/lib/logic/computation_space/problems.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/problems.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/problems.py Thu Mar 16 16:35:28 2006 @@ -87,15 +87,15 @@ cs.set_dom(v, c.FiniteDomain(dom_values)) for conf in ('c03','c04','c05','c06'): - v = cs.get_var_by_name(conf) + v = cs.find_var(conf) cs.add_constraint([v], "%s[0] == 'room C'" % v.name) for conf in ('c01','c05','c10'): - v = cs.get_var_by_name(conf) + v = cs.find_var(conf) cs.add_constraint([v], "%s[1].startswith('day 1')" % v.name) for conf in ('c02','c03','c04','c09'): - v = cs.get_var_by_name(conf) + v = cs.find_var(conf) cs.add_constraint([v], "%s[1].startswith('day 2')" % v.name) groups = (('c01','c02','c03','c10'), @@ -103,6 +103,14 @@ ('c03','c05','c06','c07'), ('c01','c03','c07','c08')) + from constraint import AllDistinct + + # for now, this has the incredible effect + # of making the solvers run forever ... +## for group in groups: +## cs.add_expression(AllDistinct(cs, tuple([cs.find_var(v) +## for v in group]))) + for g in groups: for conf1 in g: for conf2 in g: @@ -138,7 +146,7 @@ offsets = [(r,c) for r in [-1,0,1] for c in [-1,0,1]] subsquares = [(r,c) for r in [2,5,8] for c in [2,5,8]] for rc in subsquares: - sub = [cs.get_var_by_name('v%d%d'% (rc[0] + off[0],rc[1] + off[1])) for off in offsets] + sub = [cs.find_var('v%d%d'% (rc[0] + off[0],rc[1] + off[1])) for off in offsets] cs.add_constraint(sub, 'sum([%s]) == 45' % ', '.join([v.name for v in sub])) for v in sub: for m in sub[sub.index(v)+1:]: Modified: pypy/dist/pypy/lib/logic/computation_space/solvers.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/solvers.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/solvers.py Thu Mar 16 16:35:28 2006 @@ -3,19 +3,23 @@ class StrategyDistributionMismatch(Exception): pass -def dfs_one(problem): +#--- this set of solvers assumes a dichotomic distributor + +Alternatives = 2 + +def rec_solve_one(problem): """depth-first single-solution search assumes the space default distributor is dichotomic""" def do_dfs(space): - print "do_dfs" + print "do_dfs_one" status = space.ask() if status == csp.Failed: return None elif status == csp.Succeeded: return space - elif status == csp.Alternative(2): + elif status == Alternatives: new_space = space.clone() space.commit(1) outcome = do_dfs(space) @@ -34,13 +38,15 @@ #-- solve_all, switchable direction (takes problem) +from collections import deque + class Depth: pass class Breadth: pass -def solve_all(problem, direction=Depth): +def iter_solve_all(problem, direction=Depth): solutions = [] - sp_stack = [] + sp_stack = deque([]) sp_stack.append(csp.ComputationSpace(problem)) if direction == Depth: @@ -48,16 +54,17 @@ sp_stack.append(space) else: def collect(space): - sp_stack.insert(0, space) + sp_stack.appendleft(space) while len(sp_stack): + print "depth is ", len(sp_stack) space = sp_stack.pop() print ' '*len(sp_stack), "ask ..." status = space.ask() if status == csp.Succeeded: print ' '*len(sp_stack), "solution !" solutions.append(space) - elif status == csp.Alternative(2): + elif status == Alternatives: print ' '*len(sp_stack), "branches ..." sp1 = space.clone() sp1.commit(1) @@ -70,9 +77,9 @@ #-- pythonic lazy solve_all (takes space) -def lazily_solve_all(space, direction=Depth): +def lazily_iter_solve_all(space, direction=Depth): - sp_stack = [] + sp_stack = deque([]) sp_stack.append(space) if direction == Depth: @@ -80,7 +87,7 @@ sp_stack.append(space) else: def collect(space): - sp_stack.insert(0, space) + sp_stack.appendleft(space) while len(sp_stack): space = sp_stack.pop() @@ -89,7 +96,7 @@ if status == csp.Succeeded: print ' '*len(sp_stack), "solution !" yield space.merge() - elif status == csp.Alternative(2): + elif status == Alternatives: print ' '*len(sp_stack), "branches ..." sp1 = space.clone() sp1.commit(1) Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Thu Mar 16 16:35:28 2006 @@ -30,11 +30,11 @@ class TestStoreUnification: - def test_get_by_name(self): + def test_find_var(self): sp = newspace() x = sp.var('x') - assert x == sp.get_var_by_name('x') - raises(space.NotInStore, sp.get_var_by_name, 'y') + assert x == sp.find_var('x') + raises(space.NotInStore, sp.find_var, 'y') def test_add_expression(self): sp = newspace() @@ -55,7 +55,7 @@ sp.set_dom(y, c.FiniteDomain([2, 3])) sp.set_dom(z, c.FiniteDomain([3, 4])) k = c.Expression(sp, [x, y, z], 'x == y + z') - raises(c.ConsistencyFailure, k.revise3) + raises(c.ConsistencyFailure, k.revise) def test_narrowing_domains_success(self): sp = newspace() @@ -64,7 +64,7 @@ sp.set_dom(y, c.FiniteDomain([2, 3])) sp.set_dom(z, c.FiniteDomain([3, 4])) k = c.Expression(sp, [x, y, z], 'x == y + z') - k.revise3() + k.revise() assert sp.dom(x) == c.FiniteDomain([5]) assert sp.dom(y) == c.FiniteDomain([2]) assert sp.dom(z) == c.FiniteDomain([3]) @@ -75,9 +75,6 @@ class TestComputationSpace: - def setup_method(self, meth): - pass - def test_bind_cs_root(self): spc = newspace(problems.satisfiable_problem) assert '__root__' in spc.names @@ -86,7 +83,7 @@ def test_ask_alternatives(self): spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternative(2) + assert spc.ask() == 2 def test_clone(self): """checks that a chain of initially s1 = s2 @@ -119,11 +116,11 @@ space.add_constraint([y], 'y < 2') spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternative(2) + assert spc.ask() == 2 new_spc = spc.clone() new_spc.ask() new_spc.inject(more_constraints) - assert spc.ask() == space.Alternative(2) + assert spc.ask() == 2 assert new_spc.ask() == space.Succeeded def test_merge(self): @@ -134,39 +131,39 @@ space.add_constraint([y], 'y < 2') spc = newspace(problems.satisfiable_problem) - assert spc.ask() == space.Alternative(2) + assert spc.ask() == 2 new_spc = spc.clone() new_spc.ask() new_spc.inject(more_constraints) - assert spc.ask() == space.Alternative(2) + assert spc.ask() == 2 assert new_spc.ask() == space.Succeeded x, y, z = new_spc.find_vars('x', 'y', 'z') res = new_spc.merge() assert res.values() == [0, 0, 0] def test_scheduling_dfs_one_solution(self): - sol = solvers.dfs_one(problems.conference_scheduling) + sol = solvers.rec_solve_one(problems.conference_scheduling) spc = space.ComputationSpace(problems.conference_scheduling) assert spc.test_solution( sol ) def test_scheduling_all_solutions_dfs(self): - sols = solvers.solve_all(problems.conference_scheduling) + sols = solvers.iter_solve_all(problems.conference_scheduling) assert len(sols) == 64 spc = space.ComputationSpace(problems.conference_scheduling) for s in sols: assert spc.test_solution( s ) - def test_scheduling_all_solutions_lazily_dfs(self): sp = space.ComputationSpace(problems.conference_scheduling) - for sol in solvers.lazily_solve_all(sp): + for sol in solvers.lazily_iter_solve_all(sp): assert sp.test_solution(sol) def test_scheduling_all_solutions_bfs(self): - sols = solvers.solve_all(problems.conference_scheduling, - direction=solvers.Breadth) + sols = solvers.iter_solve_all(problems.conference_scheduling, + direction=solvers.Breadth) + assert len(sols) == 64 spc = space.ComputationSpace(problems.conference_scheduling) for s in sols: @@ -175,11 +172,11 @@ def test_scheduling_all_solutions_lazily_bfs(self): sp = space.ComputationSpace(problems.conference_scheduling) - for sol in solvers.lazily_solve_all(sp, direction=solvers.Breadth): + for sol in solvers.lazily_iter_solve_all(sp, direction=solvers.Breadth): assert sp.test_solution(sol) - def notest_sudoku(self): + def no_test_sudoku(self): spc = newspace(problems.sudoku) print spc.constraints @@ -193,12 +190,12 @@ for col in range(1,10): if line[col-1] != ' ': tup = ('v%d%d' % (col, row), int(line[col-1])) - space.add_constraint([space.get_var_by_name(tup[0])],'%s == %d' % tup) + space.add_constraint([space.find_var(tup[0])],'%s == %d' % tup) row += 1 spc.inject(more_constraints) print spc.constraints - sol_iter = solvers.lazily_solve_all(spc) + sol_iter = solvers.lazily_iter_solve_all(spc) sol = sol_iter.next() print sol assert spc.test_solution(sol) From ac at codespeak.net Thu Mar 16 16:38:09 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Mar 2006 16:38:09 +0100 (CET) Subject: [pypy-svn] r24480 - pypy/dist/pypy/jit/test Message-ID: <20060316153809.3831A100AB@code0.codespeak.net> Author: ac Date: Thu Mar 16 16:38:08 2006 New Revision: 24480 Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: Inprogress test. Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Thu Mar 16 16:38:08 2006 @@ -296,6 +296,22 @@ return s.n * t.n graph2, insns = abstrinterp(ll_function, [1, 0], []) +def test_merge_substructure(): + py.test.skip('Inprogress') + S = lltype.GcStruct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) + + def ll_function(flag): + t = lltype.malloc(T) + t.s.n = 3 + s = lltype.malloc(S) + s.n = 4 + if flag: + s = t.s + return s.n + graph2, insns = abstrinterp(ll_function, [0], []) + + def test_cast_pointer(): S = lltype.GcStruct('S', ('n1', lltype.Signed), ('n2', lltype.Signed)) PS = lltype.Ptr(S) From nik at codespeak.net Thu Mar 16 16:45:55 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 16:45:55 +0100 (CET) Subject: [pypy-svn] r24481 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316154555.CE015100AB@code0.codespeak.net> Author: nik Date: Thu Mar 16 16:45:54 2006 New Revision: 24481 Removed: pypy/dist/pypy/translator/squeak/message.py pypy/dist/pypy/translator/squeak/test/test_message.py Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/runtest.py Log: heavy gensqueak refactoring: * got rid of old Message class * use the new CodeFormatter for most object naming and formatting there should be some actual progress soon now ... Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Thu Mar 16 16:45:54 2006 @@ -6,7 +6,11 @@ words = identifier.split('_') return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) -class Message: +class AbstractCode: + + pass + +class Message(AbstractCode): def __init__(self, name): self.name = camel_case(name) # XXX Should not use camel_case here @@ -21,7 +25,7 @@ def send_to(self, receiver, args): return self.with_args(args).send_to(receiver) -class MessageWithArgs: +class MessageWithArgs(AbstractCode): def __init__(self, message, args): self.message = message @@ -30,7 +34,7 @@ def send_to(self, receiver): return SentMessage(self, receiver) -class SentMessage: +class SentMessage(AbstractCode): def __init__(self, message_wargs, receiver): self.message_wargs = message_wargs @@ -39,17 +43,22 @@ def assign_to(self, result): return Assignment(result, self) -class Assignment: +class Assignment(AbstractCode): def __init__(self, lvalue, rvalue): self.lvalue = lvalue self.rvalue = rvalue -class Self: +class Self(AbstractCode): pass -class Field: +class Field(AbstractCode): + + def __init__(self, name): + self.name = name + +class CustomVariable(AbstractCode): def __init__(self, name): self.name = name @@ -62,9 +71,13 @@ def format(self, code): if isinstance(code, Variable) or isinstance(code, Constant): return self.format_arg(code) - type_name = code.__class__.__name__ - method = getattr(self, "format_%s" % type_name) - return method(code) + elif isinstance(code, AbstractCode): + type_name = code.__class__.__name__ + method = getattr(self, "format_%s" % type_name) + return method(code) + else: + # Assume it's a constant value to be formatted + return self.name_constant(code) def format_arg(self, arg): """Formats Variables and Constants.""" @@ -73,27 +86,40 @@ elif isinstance(arg, Constant): if isinstance(arg.concretetype, ootype.Instance): # XXX fix this - #const_id = self.gen.unique_name( - # v, "const_%s" % self.gen.nameof(v.value._TYPE)) - #self.gen.constant_insts[v] = const_id - #return "(PyConstants getConstant: '%s')" % const_id - return None - elif arg.concretetype == ootype.Bool: - return str(arg.value).lower() - elif arg.concretetype == ootype.Void: - if isinstance(arg.value, ootype.Instance): - return self.format_Instance(arg.value) - else: - assert arg.value is None - return "nil" + const_id = self.gen.unique_name( + arg, "const_%s" % self.format_Instance(arg.value._TYPE)) + self.gen.constant_insts[arg] = const_id + return "(PyConstants getConstant: '%s')" % const_id else: - # Integers etc. - return str(arg.value) + return self.name_constant(arg.value) else: - raise TypeError, "No representation for argument %r" % (v,) + raise TypeError, "No representation for argument %r" % (arg,) + + def name_constant(self, value): + if isinstance(value, bool): + return str(value).lower() + elif isinstance(value, ootype.Instance): + return self.format_Instance(value) + elif value is None: + return "nil" + elif isinstance(value, int): + return str(value) + elif isinstance(value, ootype._class): + return self.format_Instance(value._INSTANCE) + elif isinstance(value, ootype._static_meth): + return self.gen.unique_func_name(value.graph.func) + else: + raise TypeError, "can't format constant (%s)" % value def format_Instance(self, INSTANCE): - return self.gen.nameof_Instance(INSTANCE) + if INSTANCE is None: + return "Object" + from pypy.translator.squeak.node import ClassNode + # XXX move scheduling/unique name thingies to gensqueak.py + self.gen.schedule_node(ClassNode(self.gen, INSTANCE)) + class_name = INSTANCE._name.split(".")[-1] + squeak_class_name = self.gen.unique_name(INSTANCE, class_name) + return "Py%s" % squeak_class_name def format_Self(self, _): return "self" @@ -101,6 +127,9 @@ def format_Field(self, field): return field.name + def format_CustomVariable(self, var): + return var.name + def format_MessageWithArgs(self, message): name = message.message.name arg_count = len(message.args) Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 16:45:54 2006 @@ -1,6 +1,5 @@ -from pypy.objspace.flow.model import Constant from pypy.translator.gensupp import NameManager -from pypy.translator.squeak.message import Message, camel_case +from pypy.translator.squeak.codeformatter import camel_case from pypy.translator.squeak.node import FunctionNode, ClassNode, SetupNode try: set @@ -10,12 +9,6 @@ class GenSqueak: - sqnames = { - Constant(None).key: 'nil', - Constant(False).key: 'false', - Constant(True).key: 'true', - } - def __init__(self, sqdir, translator, modname=None): self.sqdir = sqdir self.translator = translator @@ -61,45 +54,8 @@ self.pending_nodes.remove(node) self.pending_nodes.append(node) - def nameof(self, obj): - key = Constant(obj).key - try: - return self.sqnames[key] - except KeyError: - for cls in type(obj).__mro__: - meth = getattr(self, - 'nameof_' + cls.__name__.replace(' ', ''), - None) - if meth: - break - else: - types = ['nameof_'+t.__name__ for t in type(obj).__mro__] - raise Exception, "nameof(%r): no method %s" % (obj, types) - name = meth(obj) - self.sqnames[key] = name - return name - - def nameof_int(self, i): - return str(i) - - def nameof_str(self, s): - return "'s'" - - def nameof_Instance(self, INSTANCE): - if INSTANCE is None: - return "Object" - self.schedule_node(ClassNode(self, INSTANCE)) - class_name = INSTANCE._name.split(".")[-1] - squeak_class_name = self.unique_name(INSTANCE, class_name) - return "Py%s" % squeak_class_name - - def nameof__class(self, class_): - return self.nameof_Instance(class_._INSTANCE) - - def nameof__callable(self, callable): - return self.nameof_function(callable.graph.func) - - def nameof_function(self, function): + def unique_func_name(self, function): + # XXX do FunctionNode registering here squeak_func_name = self.unique_name(function, function.__name__) return squeak_func_name Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Thu Mar 16 16:45:54 2006 @@ -1,7 +1,8 @@ import datetime from pypy.objspace.flow.model import Constant, Variable -from pypy.translator.squeak.message import Message, camel_case from pypy.translator.squeak.opformatter import OpFormatter +from pypy.translator.squeak.codeformatter import CodeFormatter, Message, camel_case +from pypy.translator.squeak.codeformatter import Field, Assignment, CustomVariable from pypy.rpython.ootypesystem.ootype import Instance, ROOT class CodeNode: @@ -13,8 +14,6 @@ return isinstance(other, CodeNode) \ and self.hash_key == other.hash_key - # XXX need other comparison methods? - def render_fileout_header(self, class_name, category): return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % ( class_name, category, @@ -43,9 +42,10 @@ return [] def render(self): + codef = CodeFormatter(self.gen) yield "%s subclass: #%s" % ( - self.gen.nameof_Instance(self.INSTANCE._superclass), - self.gen.nameof_Instance(self.INSTANCE)) + codef.format_Instance(self.INSTANCE._superclass), + codef.format_Instance(self.INSTANCE)) fields = [self.unique_field(self.INSTANCE, f) for f in self.INSTANCE._fields.iterkeys()] yield " instanceVariableNames: '%s'" % ' '.join(fields) @@ -81,38 +81,26 @@ class CallableNode(CodeNode): def render_body(self, startblock): + self.codef = CodeFormatter(self.gen) self.loops = LoopFinder(startblock).loops args = self.arguments(startblock) - sel = Message(self.name) - yield sel.signature([self.expr(v) for v in args]) + message = Message(self.name).with_args(args) + yield self.codef.format(message) # XXX should declare local variables here for line in self.render_block(startblock): yield " %s" % line yield '! !' - def expr(self, v): - if isinstance(v, Variable): - return camel_case(v.name) - elif isinstance(v, Constant): - if isinstance(v.concretetype, Instance): - const_id = self.gen.unique_name( - v, "const_%s" % self.gen.nameof(v.value._TYPE)) - self.gen.constant_insts[v] = const_id - return "(PyConstants getConstant: '%s')" % const_id - return self.gen.nameof(v.value) - else: - raise TypeError, "expr(%r)" % (v,) - def render_return(self, args): if len(args) == 2: # exception - exc_cls = self.expr(args[0]) - exc_val = self.expr(args[1]) + exc_cls = self.codef.format(args[0]) + exc_val = self.codef.format(args[1]) yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) else: # regular return block - retval = self.expr(args[0]) + retval = self.codef.format(args[0]) yield "^%s" % retval def render_link(self, link): @@ -120,7 +108,8 @@ if link.args: for i in range(len(link.args)): yield '%s := %s.' % \ - (self.expr(block.inputargs[i]), self.expr(link.args[i])) + (self.codef.format(block.inputargs[i]), + self.codef.format(link.args[i])) for line in self.render_block(block): yield line @@ -147,14 +136,14 @@ if self.loops.has_key(block): if self.loops[block]: self.loops[block] = False - yield "%s] whileTrue: [" % self.expr(block.exitswitch) + yield "%s] whileTrue: [" % self.codef.format(block.exitswitch) for line in self.render_link(block.exits[True]): yield " %s" % line yield "]." for line in self.render_link(block.exits[False]): yield "%s" % line else: - yield "%s ifTrue: [" % self.expr(block.exitswitch) + yield "%s ifTrue: [" % self.codef.format(block.exitswitch) for line in self.render_link(block.exits[True]): yield " %s" % line yield "] ifFalse: [" @@ -179,8 +168,9 @@ return startblock.inputargs[1:] def render(self): + codef = CodeFormatter(self.gen) yield self.render_fileout_header( - self.gen.nameof(self.INSTANCE), "methods") + codef.format(self.INSTANCE), "methods") graph = self.INSTANCE._methods[self.name].graph self.self = graph.startblock.inputargs[0] for line in self.render_body(graph.startblock): @@ -193,7 +183,7 @@ def __init__(self, gen, graph): self.gen = gen self.graph = graph - self.name = gen.nameof(graph.func) + self.name = gen.unique_func_name(graph.func) # XXX messy self.self = None self.hash_key = graph @@ -214,6 +204,7 @@ self.gen = gen self.INSTANCE = INSTANCE self.field_name = field_name + self.codef = CodeFormatter(gen) self.hash_key = (INSTANCE, field_name, self.__class__) def dependencies(self): @@ -223,7 +214,7 @@ def render(self): yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "accessors") + self.codef.format(self.INSTANCE), "accessors") yield "%s: value" % self.field_name yield " %s := value" % self.field_name yield "! !" @@ -232,7 +223,7 @@ def render(self): yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "accessors") + self.codef.format(self.INSTANCE), "accessors") yield self.field_name yield " ^%s" % self.field_name yield "! !" @@ -271,16 +262,17 @@ return [ClassNode(self.gen, self.INSTANCE)] def render(self): + codef = CodeFormatter(self.gen) yield self.render_fileout_header( - self.gen.nameof_Instance(self.INSTANCE), "initializers") + codef.format(self.INSTANCE), "initializers") fields = self.INSTANCE._allfields() - sel = Message("field_init") - arg_names = ["a%s" % i for i in range(len(fields))] - yield sel.signature(arg_names) - for field_name, arg_name in zip(fields.keys(), arg_names): - yield " %s := %s." % ( - self.unique_field(self.INSTANCE, field_name), - arg_name) + args = [CustomVariable("a%s" % i) for i in range(len(fields))] + message = Message("field_init").with_args(args) + yield codef.format(message) + for field_name, arg in zip(fields.keys(), args): + unique_field = self.unique_field(self.INSTANCE, field_name) + ass = Assignment(Field(unique_field), arg) + yield " %s." % codef.format(ass) yield "! !" class SetupNode(CodeNode): @@ -299,26 +291,27 @@ [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] def render(self): + codef = CodeFormatter(self.gen) + # XXX use CodeFormatter throughout here yield self.render_fileout_header("PyConstants class", "internals") - sel = Message("setupConstants") - yield sel.signature([]) + message = Message("setupConstants") + yield codef.format(message.with_args([])) yield " Constants := Dictionary new." for const, const_id in self.constants.iteritems(): INST = const.value._TYPE - class_name = self.gen.nameof(INST) field_names = INST._allfields().keys() - field_values = [self.gen.nameof(getattr(const.value, f)) - for f in field_names] - init_sel = Message("field_init") - yield " Constants at: '%s' put: (%s new %s)." \ - % (const_id, class_name, - init_sel.signature(field_values)) + field_values = [getattr(const.value, f) for f in field_names] + new = Message("new").send_to(INST, []) + init_message = Message("field_init").send_to(new, field_values) + yield " Constants at: '%s' put: %s." \ + % (const_id, codef.format(init_message)) yield "! !" yield "" yield self.render_fileout_header("PyConstants class", "internals") - sel = Message("getConstant") - yield sel.signature(["constId"]) + arg = CustomVariable("constId") + get_message = Message("getConstant") + yield codef.format(get_message.with_args([arg])) yield " ^ Constants at: constId" yield "! !" Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 16:45:54 2006 @@ -129,7 +129,7 @@ def op_direct_call(self, op): from pypy.translator.squeak.node import FunctionNode - function_name = self.node.expr(op.args[0]) + function_name = self.codef.format(op.args[0]) self.gen.schedule_node( FunctionNode(self.gen, op.args[0].value.graph)) msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Thu Mar 16 16:45:54 2006 @@ -2,7 +2,6 @@ import py from pypy.tool.udir import udir from pypy.translator.squeak.gensqueak import GenSqueak -from pypy.translator.squeak.message import Message from pypy.translator.translator import TranslationContext from pypy import conftest @@ -67,6 +66,16 @@ f.close() return startup_st + def _symbol(self, arg_count): + name = self._func.__name__ + if arg_count == 0: + return name + else: + parts = [name] + if arg_count > 1: + parts += ["with"] * (arg_count - 1) + return "%s:%s" % (parts[0], "".join([p + ":" for p in parts[1:]])) + def __call__(self, *args): # NB: only integers arguments are supported currently try: @@ -86,7 +95,7 @@ options = "" cmd = 'squeak %s -- %s %s "%s" %s' \ % (options, startup_st, udir.join(self._gen.filename), - Message(self._func.__name__).symbol(len(args)), + self._symbol(len(args)), " ".join(['"%s"' % a for a in args])) squeak_process = os.popen(cmd) result = squeak_process.read() From auc at codespeak.net Thu Mar 16 17:06:50 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 16 Mar 2006 17:06:50 +0100 (CET) Subject: [pypy-svn] r24482 - pypy/dist/pypy/lib/logic/computation_space Message-ID: <20060316160650.13E7110097@code0.codespeak.net> Author: auc Date: Thu Mar 16 17:06:48 2006 New Revision: 24482 Removed: pypy/dist/pypy/lib/logic/computation_space/event.py Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py pypy/dist/pypy/lib/logic/computation_space/distributor.py Log: killed events Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Thu Mar 16 17:06:48 2006 @@ -8,7 +8,6 @@ from constraint import FiniteDomain, ConsistencyFailure, \ Expression from distributor import DefaultDistributor -import event # NewSpace, Clone, Revise Failed = 0 Succeeded = 1 @@ -163,9 +162,6 @@ return True return False - def _notify(self, event): - self.event_set.add(event) - #-- space official API ------------------------------------ def ask(self): @@ -178,7 +174,6 @@ def clone(self): spc = ComputationSpace(NoProblem, parent=self) print "-- cloning %s to %s --" % (self.id, spc.id) - self._notify(event.Clone) spc._propagate() return spc @@ -220,8 +215,9 @@ def inject(self, restricting_problem): """add additional entities into a space""" restricting_problem(self) - self._notify(event.Clone) self._propagate() + + #-- Constraint Store --------------------------------------- @@ -308,7 +304,7 @@ def _add_const(self, constraint): self.constraints.add(constraint) - self._notify(event.Inject(constraint)) + self.event_set.add(constraint) for var in constraint.affected_variables(): self.var_const_map.setdefault(var, set()) self.var_const_map[var].add(constraint) @@ -336,23 +332,11 @@ #-- Constraint propagation --------------- - def _init_constraint_queue(self): - cqueue = [] - init_const_set = set() - for ev in self.event_set: - if isinstance(ev, event.Revise): - for const in self.var_const_map[ev.var]: - init_const_set.add(const) - elif isinstance(ev, event.Inject): - init_const_set.add(ev.constraint) - - cqueue = [(const.estimate_cost(), const) - for const in init_const_set] - return cqueue - def satisfy_all(self): """really PROPAGATE from AC3""" - const_q = self._init_constraint_queue() + const_q = [(const.estimate_cost(), const) + for const in self.event_set] + self.event_set = set() assert const_q != [] const_q.sort() affected_constraints = set() Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py ============================================================================== --- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original) +++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Thu Mar 16 17:06:48 2006 @@ -1,5 +1,4 @@ import math, random -from event import Revise def arrange_domains(cs, variables): """build a data structure from var to dom @@ -139,7 +138,8 @@ int(math.floor((choice + 1) * nb_elts))) self.cs.dom(variable).remove_values(values[:start]) self.cs.dom(variable).remove_values(values[end:]) - self.cs._notify(Revise(variable)) + for const in self.cs.dependant_constraints(variable): + self.cs.event_set.add(const) class DichotomyDistributor(SplitDistributor): From bea at codespeak.net Thu Mar 16 17:20:48 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Thu, 16 Mar 2006 17:20:48 +0100 (CET) Subject: [pypy-svn] r24483 - pypy/extradoc/pypy.org Message-ID: <20060316162048.51220100A3@code0.codespeak.net> Author: bea Date: Thu Mar 16 17:20:47 2006 New Revision: 24483 Modified: pypy/extradoc/pypy.org/consortium.txt Log: put nik in there as well ;-) Modified: pypy/extradoc/pypy.org/consortium.txt ============================================================================== --- pypy/extradoc/pypy.org/consortium.txt (original) +++ pypy/extradoc/pypy.org/consortium.txt Thu Mar 16 17:20:47 2006 @@ -39,4 +39,5 @@ Laura Creighton [lac at strakt com] Eric van Riet Paap [eric at vanrietpaap nl] Richard Emslie [rxe at ukshells co uk] +Niklaus Haldimann [nhaldimann at gmx ch] From bea at codespeak.net Thu Mar 16 17:21:08 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Thu, 16 Mar 2006 17:21:08 +0100 (CET) Subject: [pypy-svn] r24484 - pypy/extradoc/pypy.org Message-ID: <20060316162108.25164100B0@code0.codespeak.net> Author: bea Date: Thu Mar 16 17:21:06 2006 New Revision: 24484 Modified: pypy/extradoc/pypy.org/index.txt Log: changed to correct number of partners Modified: pypy/extradoc/pypy.org/index.txt ============================================================================== --- pypy/extradoc/pypy.org/index.txt (original) +++ pypy/extradoc/pypy.org/index.txt Thu Mar 16 17:21:06 2006 @@ -13,7 +13,7 @@ within the Framework Programme 6, second call for proposals ("Open development platforms and services" IST). -A consortium of 7 partners in Germany, France and Sweden are working to +A consortium of 8 (12) partners in Germany, France and Sweden are working to achieve the goal of a open run-time environment for the Open Source Programming Language Python. The scientific aspects of the project is to investigate novel techniques (based on aspect-oriented programming code @@ -22,7 +22,7 @@ A methodological goal of the project is also to show case a novel software engineering process, Sprint Driven Development. This is an -Agile methodology, providing adynamic and adaptive environment, suitable +Agile methodology, providing a dynamic and adaptive environment, suitable for co-operative and distributed development. The project is divided into three major phases, phase 1 has the focus of From bea at codespeak.net Thu Mar 16 17:21:20 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Thu, 16 Mar 2006 17:21:20 +0100 (CET) Subject: [pypy-svn] r24485 - pypy/extradoc/pypy.org Message-ID: <20060316162120.4EBCB100B3@code0.codespeak.net> Author: bea Date: Thu Mar 16 17:21:19 2006 New Revision: 24485 Modified: pypy/extradoc/pypy.org/news.txt Log: updated with more news Modified: pypy/extradoc/pypy.org/news.txt ============================================================================== --- pypy/extradoc/pypy.org/news.txt (original) +++ pypy/extradoc/pypy.org/news.txt Thu Mar 16 17:21:19 2006 @@ -1,9 +1,44 @@ + + + +PyPy sprint in Louvain-La-Neuve 6-10th of March, 2006 +------------------------------------------------------- +The PyPy team sprinted at D?partement d'Ing?nierie Informatique +at UCL in Belgium. During the sprint a workshop regarding the +funcionalities of PyPy/Python and the OZ language was discussed +with people from both communities. Many thanks to our hosts at +UCL, among them Gr?goire Dooms for making this sprint possible. + + +PyPy at PyCon 24th-26th February, 2006 +---------------------------------------- +The PyPy team visited Addison/Dallas in Texas and participated +in PyCon. The PyPy team presented three talks about the status, a +architecture and methodology of the project. After the conference +ca 20 people participated in the PyPy sprint that went on for four +days. + +PyPy in Ireland 6-7th February, 2006 +--------------------------------------- +PyPy visited IONA Technologies for an experience workshop, sharing experiences +with agile and distributed software development. PyPy held two talks at +the University College Dublin for students and researchers in computer +science. Many thanks to Niall Donnely at IONA and Dr Joseph Kiniry at UCD +for hosting these events! + PyPy at the Open Source World Conference, M?laga -- February 15-17, 2006 ------------------------------------------------------------------------ PyPy is presenting at the stand of the European Commission and giving a talk on on Thursday, 14:00-15:00. +PyPy sprint in Mallorca 23-29th of January, 2006 +------------------------------------------------ +PyPy kickstarted the second year of the project with a sprint in +the GNU/Linux lab at the University of Balearic Isles on Mallorca. +The PyPy team held an architectural talk for students at the +University and met up with the local OSS group Bulma. +Many thanks to Ricardo Galli at UIB for being a gracious host! PyPy at CCC conference 27-30th of December 2005 ------------------------------------------------- From mwh at codespeak.net Thu Mar 16 17:52:49 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 16 Mar 2006 17:52:49 +0100 (CET) Subject: [pypy-svn] r24486 - pypy/extradoc/minute Message-ID: <20060316165249.60A141009D@code0.codespeak.net> Author: mwh Date: Thu Mar 16 17:52:42 2006 New Revision: 24486 Added: pypy/extradoc/minute/pypy-sync-2006-03-16.txt (contents, props changed) Log: minutes of today's meeting Added: pypy/extradoc/minute/pypy-sync-2006-03-16.txt ============================================================================== --- (empty file) +++ pypy/extradoc/minute/pypy-sync-2006-03-16.txt Thu Mar 16 17:52:42 2006 @@ -0,0 +1,128 @@ +============================================= +pypy-sync developer meeting 16th March 2006 +============================================= + + +Attendees: Samuele + Anders C. + Anders L. (arrived late) + Carl Friedrich (minutes) + Michael + Nik + Eric + +Summary +======= + + - activity reports (LAST WEEK/NEXT WEEK/BLOCKERS) + + See `the log`_ below. + + - leysin sprint details + + See the mail to pypy-dev, etc. As this is an internal only sprint + somewhere we've been before, organization is not expected to be a + major chore. + + - this "week" in pypy + + We would like to resurrect the 'this week in pypy newsletter', but + probably with a reduced, and maybe less regular, frequency. We + have one almost ready to go, but it depends on Armin writing a JIT + section and finishing up the PyCon sprint report. + +.. `the log`_ + +Complete Log +============ + + [16:09] mwh: hello + [16:09] arigo: :-) + [16:09] nikh: hola + [16:09] ericvrp: :) summertime in england? + [16:09] mwh: am i still supposed to be running the meeting + [16:09] cfbolz: yes + [16:09] mwh: ericvrp: no, i'm just at my parents' house, different distractions than normal ... + [16:10] mwh: right, activity reports please + [16:10] cfbolz: LAST: logic sprint, GC work + [16:10] cfbolz: NEXT: more GC work + [16:10] cfbolz: BLOCKERS: personal issues + [16:10] arigo: LAST: not much (setting up new laptop) + [16:10] arigo: NEXT: JIT: virtual structures, more general thinking... + [16:10] arigo: BLOCKERS: whiteness of the landscape + [16:10] arre: PREV: Bug hunting, improve performance of attribute access, some JIT work. + [16:10] arre: NEXT: More JIT. + [16:10] arre: BLOCKERS: - + [16:10] ericvrp: LAST: pyllvm setup script + [16:10] ericvrp: NEXT: pyllvm setup using llvm build tools + [16:10] ericvrp: BLOCKERS: None + [16:10] nikh: LAST: pushing gensqueak ahead + [16:10] nikh: NEXT: more pushing and pulling + [16:10] nikh: BLOCKERS: none + [16:10] auc: last : big cleanup + [16:10] auc: next : figure out how to implement 'choice' with spaces + [16:10] auc: blockers : nil + [16:10] pedronis: LAST: sprint, bug hunting, some opt and jit work, helping others + [16:10] pedronis: NEXT: more jit, more helping + [16:10] pedronis: BLOCKERS: a bit hard to focus + [16:11] mwh: LAST: GC debugging + [16:11] mwh: NEXT: more of same + [16:11] mwh: BLOCKERS: personal issues too + [16:11] mwh: i think arigo has the best blockers + [16:11] mwh: pedronis: does strakt have minders who can drag him back to gtbg? + [16:12] cfbolz: let's produce some global warming, that will fix the problem + [16:12] pedronis: I think Strakt has at least one person that would like to join him + [16:12] arre: We do have snow, just not much of it :( + [16:12] mwh: pedronis: is your 'a bit hard to focus' because all and sundry keep bugging you for help? + [16:13] pedronis: yes, there's a lot of stuff going on on all front + [16:13] mwh: i don't suppose there's much that can be done about that + [16:13] cfbolz: well, we can try to bug him less + [16:13] pedronis: no, just pointing it out as a fact + [16:14] mwh: having armin around more might shift some of the load off + [16:14] mwh: fair enough + [16:14] mwh: what else was on the agenda? + [16:14] mwh: leysin seems to be happening + [16:14] mwh: given that it's internal and we've been there before it shouldn't be the biggest of deals + [16:15] arigo: yes, I can confidently say "feel free to bug me about it" and not expect too much to happen + [16:16] nikh: what's the deadline for registering for leysin? i will be there 2 - 3 days, but don't know which yet + [16:16] mwh: i guess the only potential issue is accomodation + [16:16] mwh: do we have a block booking or something/ + [16:16] mwh: ? + [16:16] arigo: yes, there is a common booking + [16:16] arigo: there is no fixed deadline + [16:16] mwh: cool + [16:17] nikh: good. i will try to fix dates beginning next week + [16:17] arigo: I will send to the housekeeper, Arianne, the people's information as they come along + [16:17] mwh: the other topic is 'this "week" in pypy' + [16:17] mwh: we'd like to resurrect it, but probably not actually weekly + [16:18] arre: arigo: What information do you need from us? + [16:19] arigo: dates, and possibly if you'd agree to share with more than two for a couple of days (week-end days) in case of booking pressure + [16:19] arigo: mwh: monthly, or fromtimetotimely ? + [16:19] cfbolz: the latter probably + [16:19] mwh: arigo: fortnightly, maybe ? + [16:20] mwh: but perhaps not fixed + [16:20] mwh: arigo: fwiw, i have no problem with sharing with whoever + [16:21] cfbolz: anyway the point for having this "this week..." topic is to ask people to write about stuff + [16:21] arigo: there is also an extra bed at the place where I am staying, which I'd like to reserve for a non-funded person + [16:21] nikh: given that sprints are coming up pretty regularly, maybe the sprint reports could be combined with a report about what happened in the weeks before a sprint + [16:21] cfbolz: armin told me he would write a bit about the jit + [16:22] arigo: yes, I should do that as a way to come back to the topic + [16:22] arigo: until tomorrow + [16:22] cfbolz: nikh: well, I would like to keep the sprint report separate + [16:23] nikh: sure + [16:23] cfbolz: ah, I see what you mean + [16:24] nikh: it would imply a certain fixed schedule for the "this week in ..." reports + [16:24] cfbolz: yes + [16:24] cfbolz: but on the other hand, "this week" could complement the sprint reports + [16:24] cfbolz: and it should be a bit more common than sprints + [16:24] aleale joined the chat room. + [16:26] mwh: aleale: i guess you know you're late, but do you have an activity report? + [16:27] aleale: yes, sorry about that - you are not finished yet + [16:27] mwh: not quite :) + [16:27] mwh: it started late because i forgot too ... + [16:27] aleale: PREV: recovering from back to back sprinting + [16:27] aleale: NEXT: continue refactoring of pyontology + [16:27] aleale: blockers: - + [16:29] mwh: but it's now nearly half past, any other topics? + [16:29] mwh: otherwise: expect to be bugged about this week in pypy + [16:29] mwh: and see you next week! From cfbolz at codespeak.net Thu Mar 16 17:56:45 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 17:56:45 +0100 (CET) Subject: [pypy-svn] r24487 - pypy/extradoc/minute Message-ID: <20060316165645.3D54A100AB@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 17:56:38 2006 New Revision: 24487 Modified: pypy/extradoc/minute/pypy-sync-2006-03-16.txt Log: fix rest. michael did the minutes Modified: pypy/extradoc/minute/pypy-sync-2006-03-16.txt ============================================================================== --- pypy/extradoc/minute/pypy-sync-2006-03-16.txt (original) +++ pypy/extradoc/minute/pypy-sync-2006-03-16.txt Thu Mar 16 17:56:38 2006 @@ -6,8 +6,8 @@ Attendees: Samuele Anders C. Anders L. (arrived late) - Carl Friedrich (minutes) - Michael + Carl Friedrich + Michael (minutes) Nik Eric @@ -31,11 +31,13 @@ have one almost ready to go, but it depends on Armin writing a JIT section and finishing up the PyCon sprint report. -.. `the log`_ +.. _`the log`: Complete Log ============ +Complete IRC log:: + [16:09] mwh: hello [16:09] arigo: :-) [16:09] nikh: hola From nik at codespeak.net Thu Mar 16 18:13:30 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 18:13:30 +0100 (CET) Subject: [pypy-svn] r24488 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316171330.C7899100A5@code0.codespeak.net> Author: nik Date: Thu Mar 16 18:13:19 2006 New Revision: 24488 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: look again closely into nameclash issues, pass some new tests. route all unique name generation through the GenSqueak class, all node scheduling should get through there as well soon. Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Thu Mar 16 18:13:19 2006 @@ -107,19 +107,14 @@ elif isinstance(value, ootype._class): return self.format_Instance(value._INSTANCE) elif isinstance(value, ootype._static_meth): - return self.gen.unique_func_name(value.graph.func) + return self.gen.unique_func_name(value.graph) else: raise TypeError, "can't format constant (%s)" % value def format_Instance(self, INSTANCE): if INSTANCE is None: return "Object" - from pypy.translator.squeak.node import ClassNode - # XXX move scheduling/unique name thingies to gensqueak.py - self.gen.schedule_node(ClassNode(self.gen, INSTANCE)) - class_name = INSTANCE._name.split(".")[-1] - squeak_class_name = self.gen.unique_name(INSTANCE, class_name) - return "Py%s" % squeak_class_name + return self.gen.unique_class_name(INSTANCE) def format_Self(self, _): return "self" Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 18:13:19 2006 @@ -1,6 +1,7 @@ from pypy.translator.gensupp import NameManager from pypy.translator.squeak.codeformatter import camel_case from pypy.translator.squeak.node import FunctionNode, ClassNode, SetupNode +from pypy.translator.squeak.node import MethodNode try: set except NameError: @@ -54,11 +55,28 @@ self.pending_nodes.remove(node) self.pending_nodes.append(node) - def unique_func_name(self, function): - # XXX do FunctionNode registering here + def unique_func_name(self, funcgraph, schedule=True): + function = funcgraph.func squeak_func_name = self.unique_name(function, function.__name__) + if schedule: + self.schedule_node(FunctionNode(self, funcgraph)) return squeak_func_name + def unique_method_name(self, INSTANCE, method_name, schedule=True): + # XXX it's actually more complicated than that because of + # inheritance ... + squeak_method_name = self.unique_name( + (INSTANCE, method_name), method_name) + if schedule: + self.schedule_node(MethodNode(self, INSTANCE, method_name)) + return squeak_method_name + + def unique_class_name(self, INSTANCE): + self.schedule_node(ClassNode(self, INSTANCE)) + class_name = INSTANCE._name.split(".")[-1] + squeak_class_name = self.unique_name(INSTANCE, class_name) + return "Py%s" % squeak_class_name + def unique_name(self, key, basename): if self.unique_name_mapping.has_key(key): unique = self.unique_name_mapping[key] Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Thu Mar 16 18:13:19 2006 @@ -84,7 +84,7 @@ self.codef = CodeFormatter(self.gen) self.loops = LoopFinder(startblock).loops args = self.arguments(startblock) - message = Message(self.name).with_args(args) + message = Message(self.unique_name).with_args(args) yield self.codef.format(message) # XXX should declare local variables here @@ -157,6 +157,8 @@ self.gen = gen self.INSTANCE = INSTANCE self.name = method_name + self.unique_name = gen.unique_method_name( + INSTANCE, method_name, schedule=False) self.self = None # Will be set upon rendering self.hash_key = (INSTANCE, method_name) @@ -183,8 +185,9 @@ def __init__(self, gen, graph): self.gen = gen self.graph = graph - self.name = gen.unique_func_name(graph.func) # XXX messy + self.unique_name = gen.unique_func_name(graph, schedule=False) self.self = None + self._class_name = gen.unique_class_name(self.FUNCTIONS) self.hash_key = graph def dependencies(self): @@ -194,7 +197,8 @@ return startblock.inputargs def render(self): - yield self.render_fileout_header("PyFunctions class", "functions") + yield self.render_fileout_header( + "%s class" % self._class_name, "functions") for line in self.render_body(self.graph.startblock): yield line @@ -236,6 +240,7 @@ self.gen = gen self.message = message self.code = code + self._class_name = gen.unique_class_name(self.HELPERS) self.hash_key = ("helper", code) def apply(self, args): @@ -246,7 +251,8 @@ def render(self): # XXX should not use explicit name "PyHelpers" here - yield self.render_fileout_header("PyHelpers class", "helpers") + yield self.render_fileout_header( + "%s class" % self._class_name, "helpers") for line in self.code.strip().split("\n"): yield line yield "! !" @@ -282,6 +288,7 @@ def __init__(self, gen, constants): self.gen = gen self.constants = constants + self._class_name = gen.unique_class_name(self.CONSTANTS) self.hash_key = "setup" def dependencies(self): @@ -293,7 +300,8 @@ def render(self): codef = CodeFormatter(self.gen) # XXX use CodeFormatter throughout here - yield self.render_fileout_header("PyConstants class", "internals") + yield self.render_fileout_header( + "%s class" % self._class_name, "internals") message = Message("setupConstants") yield codef.format(message.with_args([])) yield " Constants := Dictionary new." @@ -308,7 +316,8 @@ yield "! !" yield "" - yield self.render_fileout_header("PyConstants class", "internals") + yield self.render_fileout_header( + "%s class" % self._class_name, "internals") arg = CustomVariable("constId") get_message = Message("getConstant") yield codef.format(get_message.with_args([arg])) Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 18:13:19 2006 @@ -84,13 +84,12 @@ def op_oosend(self, op): message_name = op.args[0].value + message_name = self.gen.unique_method_name( + op.args[1].concretetype, message_name) if op.args[1] == self.node.self: receiver = Self() else: receiver = op.args[1] - from pypy.translator.squeak.node import MethodNode - self.gen.schedule_node( - MethodNode(self.gen, op.args[1].concretetype, message_name)) sent_message = Message(message_name).send_to(receiver, op.args[2:]) return self.codef.format(sent_message.assign_to(op.result)) @@ -128,10 +127,9 @@ return self.codef.format(Assignment(op.result, op.args[0])) def op_direct_call(self, op): + # XXX how do i get rid of this import? from pypy.translator.squeak.node import FunctionNode - function_name = self.codef.format(op.args[0]) - self.gen.schedule_node( - FunctionNode(self.gen, op.args[0].value.graph)) + function_name = self.gen.unique_func_name(op.args[0].value.graph) msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) return self.codef.format(msg.assign_to(op.result)) Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 16 18:13:19 2006 @@ -39,8 +39,10 @@ from pypy.translator.squeak.test.support import A as A2 class A: def m(self, i): return 2 + i + class Functions: + def m(self, i): return 1 + i def f(): - return A().m(0) + A2().m(0) + return A().m(0) + A2().m(0) + Functions().m(-1) fn = compile_function(f) assert fn() == "3" @@ -75,6 +77,16 @@ fn = compile_function(g) assert fn() == "3" + def test_nameclash_methods(self): + class A: + def some_method(self, i): return i + 1 + def someMethod(self, i): return i + 2 + def f(): + a = A() + return a.some_method(0) + a.someMethod(0) + fn = compile_function(f) + assert fn() == "3" + def test_direct_call(self): def h(i): return g(i) + 1 # another call to g to try to trap GenSqueak From mwh at codespeak.net Thu Mar 16 18:43:07 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 16 Mar 2006 18:43:07 +0100 (CET) Subject: [pypy-svn] r24489 - pypy/extradoc/minute Message-ID: <20060316174307.D7F9D100A5@code0.codespeak.net> Author: mwh Date: Thu Mar 16 18:43:06 2006 New Revision: 24489 Modified: pypy/extradoc/minute/pypy-sync-2006-03-16.txt Log: oops, i forgot auc Modified: pypy/extradoc/minute/pypy-sync-2006-03-16.txt ============================================================================== --- pypy/extradoc/minute/pypy-sync-2006-03-16.txt (original) +++ pypy/extradoc/minute/pypy-sync-2006-03-16.txt Thu Mar 16 18:43:06 2006 @@ -6,6 +6,7 @@ Attendees: Samuele Anders C. Anders L. (arrived late) + Aurelien Campeas Carl Friedrich Michael (minutes) Nik From cfbolz at codespeak.net Thu Mar 16 20:35:33 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Mar 2006 20:35:33 +0100 (CET) Subject: [pypy-svn] r24491 - pypy/dist/pypy/translator/backendopt Message-ID: <20060316193533.8B26C100AC@code0.codespeak.net> Author: cfbolz Date: Thu Mar 16 20:35:32 2006 New Revision: 24491 Modified: pypy/dist/pypy/translator/backendopt/inline.py Log: try to make inlining behave a bit less quadratical :-) don't search for calls to the to-be-inlined function all over again after inlining one call. just look in blocks that actually changed Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Thu Mar 16 20:35:32 2006 @@ -39,16 +39,15 @@ def iter_callsites(graph, calling_what): for block in graph.iterblocks(): - if isinstance(block, Block): - for i, op in enumerate(block.operations): - if not op.opname == "direct_call": - continue - funcobj = op.args[0].value._obj - graph = getattr(funcobj, 'graph', None) - # accept a function or a graph as 'inline_func' - if (graph is calling_what or - getattr(funcobj, '_callable', None) is calling_what): - yield graph, block, i + for i, op in enumerate(block.operations): + if not op.opname == "direct_call": + continue + funcobj = op.args[0].value._obj + graph = getattr(funcobj, 'graph', None) + # accept a function or a graph as 'inline_func' + if (graph is calling_what or + getattr(funcobj, '_callable', None) is calling_what): + yield graph, block, i def find_callsites(graph, calling_what): return list(iter_callsites(graph, calling_what)) @@ -69,19 +68,8 @@ return False def inline_function(translator, inline_func, graph): - count = 0 - for subgraph, block, index_operation in iter_first_callsites(graph, inline_func): - if contains_call(subgraph, subgraph): - raise CannotInline("inlining a recursive function") - operation = block.operations[index_operation] - if getattr(operation, "cleanup", None) is not None: - finallyops, exceptops = operation.cleanup - if finallyops or exceptops: - raise CannotInline("cannot inline a function with cleanup attached") - _inline_function(translator, graph, block, index_operation) - checkgraph(graph) - count += 1 - return count + inliner = Inliner(translator, graph, inline_func) + return inliner.inline_all() def _find_exception_type(block): #XXX slightly brittle: find the exception type for simple cases @@ -101,11 +89,39 @@ class Inliner(object): - def __init__(self, translator, graph, block, index_operation): + def __init__(self, translator, graph, inline_func): self.translator = translator self.graph = graph + self.inline_func = inline_func + callsites = find_callsites(graph, inline_func) + self.block_to_index = {} + for g, block, i in callsites: + self.block_to_index.setdefault(block, {})[i] = g + + def inline_all(self): + count = 0 + non_recursive = {} + while self.block_to_index: + block, d = self.block_to_index.popitem() + index_operation, subgraph = d.popitem() + if d: + self.block_to_index[block] = d + if subgraph not in non_recursive and contains_call(subgraph, subgraph): + raise CannotInline("inlining a recursive function") + else: + non_recursive[subgraph] = True + operation = block.operations[index_operation] + if getattr(operation, "cleanup", None) is not None: + finallyops, exceptops = operation.cleanup + if finallyops or exceptops: + raise CannotInline("cannot inline a function with cleanup attached") + self.inline_once(block, index_operation) + count += 1 + self.cleanup() + return count + + def inline_once(self, block, index_operation): self.varmap = {} - self.beforeblock = block self._copied_blocks = {} self._copied_cleanups = {} self.op = block.operations[index_operation] @@ -119,7 +135,25 @@ self._passon_vars = {} self.entrymap = mkentrymap(self.graph_to_inline) self.do_inline(block, index_operation) - self.cleanup() + + def search_for_calls(self, block): + d = {} + for i, op in enumerate(block.operations): + if not op.opname == "direct_call": + continue + funcobj = op.args[0].value._obj + graph = getattr(funcobj, 'graph', None) + # accept a function or a graph as 'inline_func' + if (graph is self.inline_func or + getattr(funcobj, '_callable', None) is self.inline_func): + d[i] = graph + if d: + self.block_to_index[block] = d + else: + try: + del self.block_to_index[block] + except KeyError: + pass def get_new_name(self, var): if var is None: @@ -172,6 +206,7 @@ newblock.exits = [self.copy_link(link, block) for link in block.exits] newblock.exitswitch = self.get_new_name(block.exitswitch) newblock.exc_handler = block.exc_handler + self.search_for_calls(newblock) return newblock def copy_link(self, link, prevblock): @@ -322,11 +357,11 @@ # the inlined function # for every inserted block we need a new copy of these variables, # this copy is created with the method passon_vars - self.original_passon_vars = [arg for arg in self.beforeblock.exits[0].args + self.original_passon_vars = [arg for arg in block.exits[0].args if isinstance(arg, Variable)] assert afterblock.operations[0] is self.op #vars that need to be passed through the blocks of the inlined function - linktoinlined = self.beforeblock.exits[0] + linktoinlined = block.exits[0] assert linktoinlined.target is afterblock copiedstartblock = self.copy_block(self.graph_to_inline.startblock) copiedstartblock.isstartblock = False @@ -352,6 +387,8 @@ assert afterblock.exits[0].exitcase is None afterblock.exits = [afterblock.exits[0]] afterblock.exitswitch = None + self.search_for_calls(afterblock) + self.search_for_calls(block) def cleanup(self): """ cleaning up -- makes sense to be done after inlining, because the @@ -363,7 +400,9 @@ remove_identical_vars(self.graph) -_inline_function = Inliner +def _inline_function(translator, graph, block, index_operation): + inline_func = block.operations[index_operation].args[0].value._obj._callable + inliner = Inliner(translator, graph, inline_func) # ____________________________________________________________ # From nik at codespeak.net Thu Mar 16 21:45:37 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 21:45:37 +0100 (CET) Subject: [pypy-svn] r24493 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316204537.DAC34100AC@code0.codespeak.net> Author: nik Date: Thu Mar 16 21:45:36 2006 New Revision: 24493 Modified: pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: somewhat resolve unique field name issues. Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Thu Mar 16 21:45:36 2006 @@ -1,7 +1,7 @@ from pypy.translator.gensupp import NameManager from pypy.translator.squeak.codeformatter import camel_case from pypy.translator.squeak.node import FunctionNode, ClassNode, SetupNode -from pypy.translator.squeak.node import MethodNode +from pypy.translator.squeak.node import MethodNode, SetterNode, GetterNode try: set except NameError: @@ -77,7 +77,22 @@ squeak_class_name = self.unique_name(INSTANCE, class_name) return "Py%s" % squeak_class_name + def unique_field_name(self, INSTANCE, field_name, schedule=True): + # XXX nameclashes with superclasses must be considered, too. + while not INSTANCE._fields.has_key(field_name): + # This is necessary to prevent a field from having different + # unique names in different subclasses. + INSTANCE = INSTANCE._superclass + if schedule: + # Generating getters and setters for all fields by default which + # is potentially a waste, but easier for now. + self.schedule_node(SetterNode(self, INSTANCE, field_name)) + self.schedule_node(GetterNode(self, INSTANCE, field_name)) + return self.unique_name( + (INSTANCE, "field", field_name), field_name) + def unique_name(self, key, basename): + # XXX should account for squeak keywords here if self.unique_name_mapping.has_key(key): unique = self.unique_name_mapping[key] else: @@ -86,4 +101,3 @@ self.unique_name_mapping[key] = unique return unique - Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Thu Mar 16 21:45:36 2006 @@ -19,12 +19,6 @@ class_name, category, datetime.datetime.now().strftime("%m/%d/%Y %H:%M")) - def unique_field(self, INSTANCE, field_name): - # XXX for now we ignore the issue of nameclashes between - # field names. It's not so simple because superclasses must - # be considered, too. - return camel_case(field_name) - class ClassNode(CodeNode): def __init__(self, gen, INSTANCE, class_vars=None): @@ -36,17 +30,17 @@ self.hash_key = INSTANCE def dependencies(self): + deps = [] if self.INSTANCE._superclass is not None: # not root - return [ClassNode(self.gen, self.INSTANCE._superclass)] - else: - return [] + deps.append(ClassNode(self.gen, self.INSTANCE._superclass)) + return deps def render(self): codef = CodeFormatter(self.gen) yield "%s subclass: #%s" % ( codef.format_Instance(self.INSTANCE._superclass), codef.format_Instance(self.INSTANCE)) - fields = [self.unique_field(self.INSTANCE, f) for f in + fields = [self.gen.unique_field_name(self.INSTANCE, f) for f in self.INSTANCE._fields.iterkeys()] yield " instanceVariableNames: '%s'" % ' '.join(fields) yield " classVariableNames: '%s'" % ' '.join(self.class_vars) @@ -208,6 +202,8 @@ self.gen = gen self.INSTANCE = INSTANCE self.field_name = field_name + self.unique_name = gen.unique_field_name( + INSTANCE, field_name, schedule=False) self.codef = CodeFormatter(gen) self.hash_key = (INSTANCE, field_name, self.__class__) @@ -219,8 +215,8 @@ def render(self): yield self.render_fileout_header( self.codef.format(self.INSTANCE), "accessors") - yield "%s: value" % self.field_name - yield " %s := value" % self.field_name + yield "%s: value" % self.unique_name + yield " %s := value" % self.unique_name yield "! !" class GetterNode(AccessorNode): @@ -228,8 +224,8 @@ def render(self): yield self.render_fileout_header( self.codef.format(self.INSTANCE), "accessors") - yield self.field_name - yield " ^%s" % self.field_name + yield self.unique_name + yield " ^%s" % self.unique_name yield "! !" class HelperNode(CodeNode): @@ -276,7 +272,7 @@ message = Message("field_init").with_args(args) yield codef.format(message) for field_name, arg in zip(fields.keys(), args): - unique_field = self.unique_field(self.INSTANCE, field_name) + unique_field = self.gen.unique_field_name(self.INSTANCE, field_name) ass = Assignment(Field(unique_field), arg) yield " %s." % codef.format(ass) yield "! !" Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 21:45:36 2006 @@ -75,6 +75,7 @@ sent_message = message.send_to(op.args[0], op.args[1:]) if opname in self.wrapping_ops \ and self.int_masks.has_key(ptype): + # XXX how do i get rid of this import? from pypy.translator.squeak.node import HelperNode mask_name, mask_code = self.int_masks[ptype] helper = HelperNode(self.gen, Message(mask_name), mask_code) @@ -95,7 +96,7 @@ def op_oogetfield(self, op): INST = op.args[0].concretetype - field_name = self.node.unique_field(INST, op.args[1].value) + field_name = self.gen.unique_field_name(INST, op.args[1].value) if op.args[0] == self.node.self: # Private field access # Could also directly substitute op.result with name @@ -103,23 +104,19 @@ rvalue = Field(field_name) else: # Public field access - from pypy.translator.squeak.node import GetterNode - self.gen.schedule_node(GetterNode(self.gen, INST, field_name)) rvalue = Message(field_name).send_to(op.args[0], []) return self.codef.format(Assignment(op.result, rvalue)) def op_oosetfield(self, op): # Note that the result variable is never used INST = op.args[0].concretetype - field_name = self.node.unique_field(INST, op.args[1].value) + field_name = self.gen.unique_field_name(INST, op.args[1].value) field_value = op.args[2] if op.args[0] == self.node.self: # Private field access return self.codef.format(Assignment(Field(field_name), field_value)) else: # Public field access - from pypy.translator.squeak.node import SetterNode - self.gen.schedule_node(SetterNode(self.gen, INST, field_name)) setter = Message(field_name).send_to(op.args[0], [field_value]) return self.codef.format(setter) Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Thu Mar 16 21:45:36 2006 @@ -87,6 +87,18 @@ fn = compile_function(f) assert fn() == "3" + def test_nameclash_fields(self): + class A: + def m(self, i): + self.var1 = i + self.var_1 = i + 1 + def f(): + a = A() + a.m(1) + return a.var1 + a.var_1 + fn = compile_function(f) + assert fn() == "3" + def test_direct_call(self): def h(i): return g(i) + 1 # another call to g to try to trap GenSqueak From nik at codespeak.net Thu Mar 16 21:54:34 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Thu, 16 Mar 2006 21:54:34 +0100 (CET) Subject: [pypy-svn] r24494 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060316205434.3CD53100B7@code0.codespeak.net> Author: nik Date: Thu Mar 16 21:54:33 2006 New Revision: 24494 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: make some more integer llop tests pass, just to feel some actual progress after all this refactoring ... Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Thu Mar 16 21:54:33 2006 @@ -44,6 +44,8 @@ 'mul': '*', 'div': '//', 'floordiv': '//', + #'truediv': '/',: '/', + 'mod': r'\\', } number_opprefixes = "int", "uint", "llong", "ullong", "float" Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Thu Mar 16 21:54:33 2006 @@ -52,6 +52,8 @@ ("div", Signed, 7, 3), ("floordiv", Signed, 7, 3), ("floordiv", Signed, -7, 3), + ("mod", Signed, 9, 4), + ("mod", Signed, 9, -4), ] def test_intoperations(): @@ -68,6 +70,7 @@ tests = adapt_tests(general_tests, r_uint, Unsigned, "uint") + [ # binary wraparounds ("uint_add", Unsigned, r_uint(2*sys.maxint), r_uint(2)), + ("uint_sub", Unsigned, r_uint(1), r_uint(3)), ("uint_mul", Unsigned, r_uint(sys.maxint), r_uint(3)), ] for t in tests: From tismer at codespeak.net Thu Mar 16 23:02:36 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 16 Mar 2006 23:02:36 +0100 (CET) Subject: [pypy-svn] r24496 - pypy/dist/pypy/interpreter Message-ID: <20060316220236.A6004100CC@code0.codespeak.net> Author: tismer Date: Thu Mar 16 23:02:28 2006 New Revision: 24496 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: detabbing Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 16 23:02:28 2006 @@ -46,12 +46,12 @@ subcontext_new = staticmethod(subcontext_new) def subcontext_switch(self, current, next): - current.framestack = self.framestack + current.framestack = self.framestack current.w_tracefunc = self.w_tracefunc current.w_profilefunc = self.w_profilefunc current.is_tracing = self.is_tracing - self.framestack = next.framestack + self.framestack = next.framestack self.w_tracefunc = next.w_tracefunc self.w_profilefunc = next.w_profilefunc self.is_tracing = next.is_tracing From cfbolz at codespeak.net Fri Mar 17 00:13:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 00:13:18 +0100 (CET) Subject: [pypy-svn] r24497 - in pypy/dist/pypy/translator: . test Message-ID: <20060316231318.67CDD100D7@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 00:13:16 2006 New Revision: 24497 Modified: pypy/dist/pypy/translator/simplify.py pypy/dist/pypy/translator/test/test_simplify.py Log: (mwh, cfbolz): fix join_blocks to use an explicit stack: we were getting stack overflows, because of huge graphs that arose because of lots of push/pops being inlined in already large functions. Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Fri Mar 17 00:13:16 2006 @@ -293,46 +293,49 @@ block (but renaming variables with the appropriate arguments.) """ entrymap = mkentrymap(graph) - - def visit(link): - if isinstance(link, Link): - if (len(link.prevblock.exits) == 1 and - len(entrymap[link.target]) == 1 and - link.target.exits): # stop at the returnblock - renaming = {} - cache_cleanups = {} - for vprev, vtarg in zip(link.args, link.target.inputargs): - renaming[vtarg] = vprev - def rename(v): - return renaming.get(v, v) - def rename_op(op): - args = [rename(a) for a in op.args] - if hasattr(op, "cleanup"): - if op.cleanup is None: - cleanup = None - elif op.cleanup not in cache_cleanups: - finallyops, exceptops = op.cleanup - cleanup = (tuple([rename_op(fo) for fo in finallyops]), - tuple([rename_op(eo) for eo in exceptops])) - cache_cleanups[op.cleanup] = cleanup - else: - cleanup = cache_cleanups[op.cleanup] - op = SpaceOperation(op.opname, args, rename(op.result), cleanup=cleanup) + block = graph.startblock + seen = {block: True} + stack = list(block.exits) + while stack: + link = stack.pop() + if (len(link.prevblock.exits) == 1 and + len(entrymap[link.target]) == 1 and + link.target.exits): # stop at the returnblock + renaming = {} + cache_cleanups = {} + for vprev, vtarg in zip(link.args, link.target.inputargs): + renaming[vtarg] = vprev + def rename(v): + return renaming.get(v, v) + def rename_op(op): + args = [rename(a) for a in op.args] + if hasattr(op, "cleanup"): + if op.cleanup is None: + cleanup = None + elif op.cleanup not in cache_cleanups: + finallyops, exceptops = op.cleanup + cleanup = (tuple([rename_op(fo) for fo in finallyops]), + tuple([rename_op(eo) for eo in exceptops])) + cache_cleanups[op.cleanup] = cleanup else: - op = SpaceOperation(op.opname, args, rename(op.result)) - return op - for op in link.target.operations: - link.prevblock.operations.append(rename_op(op)) - exits = [] - for exit in link.target.exits: - newexit = exit.copy(rename) - exits.append(newexit) - link.prevblock.exitswitch = rename(link.target.exitswitch) - link.prevblock.recloseblock(*exits) - # simplify recursively the new links - for exit in exits: - visit(exit) - traverse(visit, graph) + cleanup = cache_cleanups[op.cleanup] + op = SpaceOperation(op.opname, args, rename(op.result), cleanup=cleanup) + else: + op = SpaceOperation(op.opname, args, rename(op.result)) + return op + for op in link.target.operations: + link.prevblock.operations.append(rename_op(op)) + exits = [] + for exit in link.target.exits: + newexit = exit.copy(rename) + exits.append(newexit) + link.prevblock.exitswitch = rename(link.target.exitswitch) + link.prevblock.recloseblock(*exits) + stack.extend(exits) + else: + if link.target not in seen: + stack.extend(link.target.exits) + seen[link.target] = True def remove_assertion_errors(graph): """Remove branches that go directly to raising an AssertionError, Modified: pypy/dist/pypy/translator/test/test_simplify.py ============================================================================== --- pypy/dist/pypy/translator/test/test_simplify.py (original) +++ pypy/dist/pypy/translator/test/test_simplify.py Fri Mar 17 00:13:16 2006 @@ -127,3 +127,13 @@ graph = get_graph(op.args[0], t) assert graph is None +def addone(x): + return x + 1 + +def test_huge_func(): + g = None + gstring = "def g(x):\n%s%s" % (" x = x + 1\n" * 1000, " return x\n") + exec gstring + assert g(1) == 1001 + # does not crash: previously join_blocks would barf on this + graph, t = translate(g, [int]) From mwh at codespeak.net Fri Mar 17 01:37:30 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 17 Mar 2006 01:37:30 +0100 (CET) Subject: [pypy-svn] r24500 - pypy/dist/pypy/doc/weekly Message-ID: <20060317003730.7FB02100CC@code0.codespeak.net> Author: mwh Date: Fri Mar 17 01:37:26 2006 New Revision: 24500 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: pypy-c _finally_ built, so add some (not too good) performance numbers. looking at the c source reveals that the inlining is not as thorough as we might have liked for a sort of "haha" reason: direct_calls in 'finally' cleanups are not inlined (presumably 'except' cleanups have the same problem). maybe it should be an except block and a cleanup block, or something. Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Fri Mar 17 01:37:26 2006 @@ -48,7 +48,10 @@ This week Michael with the help of Carl, Samuele and Armin managed for the first time to compile the pypy interpreter together with our own -garbage collector written in Python. XXX performance numbers go here. +garbage collector written in Python. Performance is not that great as +yet, about 100 times slower than CPython or about 16 times slower than +with the Boehm collector. Given that we haven't tuned our garbage +collector for performance at all, this isn't too bad. This required quite a bit of work and first we refactored the way the existing two garbage collectors (reference counting and using the Boehm From tismer at codespeak.net Fri Mar 17 05:36:15 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 17 Mar 2006 05:36:15 +0100 (CET) Subject: [pypy-svn] r24502 - pypy/dist/pypy/rpython/memory Message-ID: <20060317043615.D7E32100D3@code0.codespeak.net> Author: tismer Date: Fri Mar 17 05:36:04 2006 New Revision: 24502 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: a quick hack to make the protect operations correct. There is currently an ambiguity in handling certain situations, since we loose information after operations are rewritten. Actually, the fact that gc_protect is implemented by a direct_call, this should not mean that this call can raise. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Fri Mar 17 05:36:04 2006 @@ -12,6 +12,7 @@ import sets, os EXCEPTION_RAISING_OPS = ['direct_call', 'indirect_call'] +NEVER_RAISING_OPS = ['gc_protect', 'gc_unprotect'] def var_needsgc(var): if hasattr(var, 'concretetype'): @@ -113,9 +114,11 @@ if not ops: continue # may happen when we eat gc_protect/gc_unprotect. newops.extend(ops) + origname = op.opname op = ops[-1-num_ops_after_exc_raising] # XXX for now we assume that everything can raise - if 1 or op.opname in EXCEPTION_RAISING_OPS: + # XXX quick hack to make the protect stuff not add exception handling + if origname not in NEVER_RAISING_OPS and (1 or op.opname in EXCEPTION_RAISING_OPS): if tuple(livevars) in livevars2cleanup: cleanup_on_exception = livevars2cleanup[tuple(livevars)] else: From goden at codespeak.net Fri Mar 17 05:57:59 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Fri, 17 Mar 2006 05:57:59 +0100 (CET) Subject: [pypy-svn] r24503 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20060317045759.19BBD100D3@code0.codespeak.net> Author: goden Date: Fri Mar 17 05:57:55 2006 New Revision: 24503 Modified: pypy/dist/pypy/rpython/rctypes/implementation.py pypy/dist/pypy/rpython/rctypes/interface.py pypy/dist/pypy/rpython/rctypes/rprimitive.py pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: removed references to the R* versions of POINTER, ARRAY, and byref from interface.py. took a stab at fixing the annotation and translation of ctypes function calls by adding lookups to the extregistry. appears to work for primitive types. re-enabled some of the tests in test_rctypes.py which pass. Modified: pypy/dist/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/implementation.py (original) +++ pypy/dist/pypy/rpython/rctypes/implementation.py Fri Mar 17 05:57:55 2006 @@ -83,10 +83,22 @@ CFuncPtrType = type(ctypes.CFUNCTYPE(None)) def cfuncptrtype_compute_annotation(type, instance): + from pypy.annotation.model import ll_to_annotation_map + def compute_result_annotation(*args_s): """ Answer the annotation of the external function's result """ + + # results of external function calls *must* be in the registry + # XXX: goden: check metatype too? + assert extregistry.is_registered_type(instance.restype) + + entry = extregistry.lookup_type(instance.restype) + + # XXX: goden: this probably isn't right + return ll_to_annotation_map.get(entry.lowleveltype) + # Take 3, Check whether we can get away with the cheap # precomputed solution and if not it, use a special # attribute with the memory state @@ -126,10 +138,15 @@ answer.append(ctype_type.wrap_arg(ll_type, arg_name)) return answer + assert extregistry.is_registered_type(cfuncptr.restype) + + # results of external function calls *must* be in the registry + entry = extregistry.lookup_type(cfuncptr.restype) + return hop.llops.gencapicall( cfuncptr.__name__, hop.args_v, - resulttype = cfuncptr.restype.ll_type, + resulttype = entry.lowleveltype, _callable=None, convert_params = convert_params ) Modified: pypy/dist/pypy/rpython/rctypes/interface.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/interface.py (original) +++ pypy/dist/pypy/rpython/rctypes/interface.py Fri Mar 17 05:57:55 2006 @@ -3,8 +3,7 @@ c_char, c_byte, c_ubyte, \ c_short, c_ushort, c_uint,\ c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, \ - RStructure as Structure, RByref as byref, RPOINTER as POINTER, \ - ARRAY + Structure, byref, POINTER, ARRAY #try: # from implementation import RWinDLL as WinDLL #except ImportError: Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rprimitive.py (original) +++ pypy/dist/pypy/rpython/rctypes/rprimitive.py Fri Mar 17 05:57:55 2006 @@ -104,6 +104,7 @@ def compute_result_annotation_function(s_arg=None): return annmodel.SomeCTypesObject(the_type, annmodel.SomeCTypesObject.OWNSMEMORY) + extregistry.register_value(the_type, compute_result_annotation=compute_result_annotation_function, specialize_call=primitive_specialize_call Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Fri Mar 17 05:57:55 2006 @@ -43,7 +43,7 @@ py.test.skip("this test needs ctypes installed") -py.test.skip("these tests are broken while the ctypes primitive types are ported to use the extregistry") +#py.test.skip("these tests are broken while the ctypes primitive types are ported to use the extregistry") from pypy.rpython.rctypes import cdll, c_char_p, c_int, c_char, \ c_char, c_byte, c_ubyte, c_short, c_ushort, c_uint,\ @@ -303,7 +303,7 @@ res = py_testfunc_struct(in_point) assert res == 30 - def test_annotate_struct(self): + def x_test_annotate_struct(self): a = RPythonAnnotator() s = a.build_types(py_testfunc_struct, [tagpoint]) assert s.knowntype == int @@ -311,14 +311,14 @@ if conftest.option.view: a.translator.view() - def test_annotate_struct2(self): + def x_test_annotate_struct2(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_struct_id, [tagpoint]) assert s.knowntype == tagpoint assert s.memorystate == SomeCTypesObject.OWNSMEMORY - def test_annotate_pointer_to_struct(self): + def x_test_annotate_pointer_to_struct(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_struct_pointer_id, [oppoint_type]) @@ -326,7 +326,7 @@ assert s.memorystate == SomeCTypesObject.MEMORYALIAS return t - def test_create_point(self): + def x_test_create_point(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_create_point,[]) @@ -335,7 +335,7 @@ if conftest.option.view: a.translator.view() - def test_annotate_byval(self): + def x_test_annotate_byval(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_byval,[tagpoint]) @@ -345,7 +345,7 @@ assert s.items[1].knowntype == tagpoint assert s.items[1].memorystate == SomeCTypesObject.OWNSMEMORY - def test_annotate_POINTER(self): + def x_test_annotate_POINTER(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_POINTER,[tagpoint]) @@ -356,7 +356,7 @@ assert s.items[1].memorystate == SomeCTypesObject.OWNSMEMORY #d#t.view() - def test_annotate_POINTER_dereference(self): + def x_test_annotate_POINTER_dereference(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_POINTER_dereference, [tagpoint]) @@ -369,7 +369,7 @@ assert s.items[2].memorystate == SomeCTypesObject.OWNSMEMORY #d#t.view() - def test_annotate_mixed_memorystate(self): + def x_test_annotate_mixed_memorystate(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_test_mixed_memory_state, [int]) @@ -409,7 +409,7 @@ s = a.build_types(py_test_simple_ctypes_non_const,[]) assert s.knowntype == c_float - def test_specialize_struct(self): + def x_test_specialize_struct(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_test_specialize_struct, []) @@ -421,7 +421,7 @@ if conftest.option.view: t.view() - def test_specialize_struct_1(self): + def x_test_specialize_struct_1(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_test_compile_struct, [int, int]) @@ -432,7 +432,7 @@ #d#t.view() pass - def test_specialize_pointer_to_struct(self): + def x_test_specialize_pointer_to_struct(self): t = self.test_annotate_pointer_to_struct() t.buildrtyper().specialize() if conftest.option.view: @@ -441,12 +441,12 @@ def x_test_compile_pointer_to_struct(self): fn = compile( py_testfunc_struct_pointer_id, [ oppoint_type ] ) - def test_compile_struct(self): + def x_test_compile_struct(self): fn = compile( py_test_compile_struct, [ int, int ] ) res = fn( 42, -42 ) assert res == 42 - def test_specialize_POINTER_dereference(self): + def x_test_specialize_POINTER_dereference(self): t = TranslationContext() a = t.buildannotator() s = a.build_types(py_testfunc_POINTER_dereference, [tagpoint]) @@ -457,7 +457,7 @@ #d#t.view() pass - def test_specialize_pointer(self): + def x_test_specialize_pointer(self): t = TranslationContext() a = t.buildannotator() s = a.build_types( py_test_compile_pointer, [ int, int ] ) @@ -466,7 +466,7 @@ t.buildrtyper().specialize() #d#t.view() - def test_compile_pointer(self): + def x_test_compile_pointer(self): fn = compile( py_test_compile_pointer, [ int, int ] ) res = fn( -42, 42 ) assert res == -42 From tismer at codespeak.net Fri Mar 17 06:31:43 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 17 Mar 2006 06:31:43 +0100 (CET) Subject: [pypy-svn] r24504 - pypy/dist/pypy/rpython/memory/test Message-ID: <20060317053143.A423A100D2@code0.codespeak.net> Author: tismer Date: Fri Mar 17 06:31:28 2006 New Revision: 24504 Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: adjusted test to what I learned from Armin Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Fri Mar 17 06:31:28 2006 @@ -220,19 +220,15 @@ def test_protect_unprotect(): def protect(obj): RaiseNameError def unprotect(obj): RaiseNameError - def rtype_protect(hop): - v_any, = hop.inputargs(hop.args_r[0]) - return hop.genop('gc_protect', [v_any], resulttype=lltype.Void) - def rtype_unprotect(hop): - v_any, = hop.inputargs(hop.args_r[0]) - return hop.genop('gc_unprotect', [v_any], resulttype=lltype.Void) + def rtype_protect(hop): hop.genop('gc_protect', [hop.inputargs(hop.args_r[0])[0]]) + def rtype_unprotect(hop): hop.genop('gc_unprotect', [hop.inputargs(hop.args_r[0])[0]]) extregistry.register_value(protect, - compute_result_annotation=annmodel.s_None, specialize_call=rtype_protect) + compute_result_annotation=lambda *args: None, specialize_call=rtype_protect) extregistry.register_value(unprotect, - compute_result_annotation=annmodel.s_None, specialize_call=rtype_unprotect) + compute_result_annotation=lambda *args: None, specialize_call=rtype_unprotect) - def p(): return protect('this is an object') - def u(): return unprotect('this is an object') + def p(): protect('this is an object') + def u(): unprotect('this is an object') rgc = gctransform.RefcountingGCTransformer bgc = gctransform.BoehmGCTransformer From arigo at codespeak.net Fri Mar 17 11:57:43 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 17 Mar 2006 11:57:43 +0100 (CET) Subject: [pypy-svn] r24515 - in pypy/dist/pypy/jit: . test Message-ID: <20060317105743.E29E6100D3@code0.codespeak.net> Author: arigo Date: Fri Mar 17 11:57:42 2006 New Revision: 24515 Modified: pypy/dist/pypy/jit/llcontainer.py pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: llabstractinterp: merging virtual substructures require matching the whole structure. Modified: pypy/dist/pypy/jit/llcontainer.py ============================================================================== --- pypy/dist/pypy/jit/llcontainer.py (original) +++ pypy/dist/pypy/jit/llcontainer.py Fri Mar 17 11:57:42 2006 @@ -98,6 +98,13 @@ if self.__class__ is not live.__class__: return False + if self.a_parent is not None: + if (live.a_parent is None or + not self.a_parent.match(live.a_parent, memo)): + return False + elif live.a_parent is not None: + return False + if self in memo.self_alias: return live is memo.self_alias[self] if live in memo.live_alias: Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Fri Mar 17 11:57:42 2006 @@ -297,7 +297,6 @@ graph2, insns = abstrinterp(ll_function, [1, 0], []) def test_merge_substructure(): - py.test.skip('Inprogress') S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) From nik at codespeak.net Fri Mar 17 12:25:05 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 17 Mar 2006 12:25:05 +0100 (CET) Subject: [pypy-svn] r24516 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060317112505.C8126100D6@code0.codespeak.net> Author: nik Date: Fri Mar 17 12:24:59 2006 New Revision: 24516 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: support (almost) all integer operations for all integer types. Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Fri Mar 17 12:24:59 2006 @@ -5,8 +5,8 @@ def _setup_int_masks(): """Generates code for helpers to mask the various integer types.""" masks = {} - for name, r_type in ("int", r_int), ("uint", r_uint), \ - ("llong", r_longlong), ("ullong", r_ulonglong): + # NB: behaviour of signed long longs is undefined on overflow + for name, r_type in ("int", r_int), ("uint", r_uint), ("ullong", r_ulonglong): helper_name = "mask%s" % name.capitalize() if name[0] == "u": # Unsigned integer type @@ -36,7 +36,7 @@ 'abs': 'abs', 'is_true': 'isZero not', 'neg': 'negated', - 'invert': 'bitInvert', # maybe bitInvert32? + 'invert': 'bitInvert', 'add': '+', 'sub': '-', @@ -44,13 +44,25 @@ 'mul': '*', 'div': '//', 'floordiv': '//', - #'truediv': '/',: '/', + #'truediv': '/', # XXX fix this when we have float support 'mod': r'\\', + 'eq': '=', + 'ne': '~=', + 'lt': '<', + 'le': '<=', + 'gt': '>', + 'ge': '>=', + 'and': 'bitAnd', + 'or': 'bitOr', + 'lshift': '<<', + 'rshift': '>>', + 'xor': 'bitXor', + # XXX need to support x_ovf ops } number_opprefixes = "int", "uint", "llong", "ullong", "float" - wrapping_ops = "neg", "invert", "add", "sub", "mul" + wrapping_ops = "neg", "invert", "add", "sub", "mul", "lshift" int_masks = _setup_int_masks() Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Fri Mar 17 12:24:59 2006 @@ -1,9 +1,10 @@ import sys from pypy.translator.squeak.test.runtest import compile_function -from pypy.rpython.rarithmetic import r_uint +from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Bool +from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong from pypy.rpython.test.test_llinterp import interpret def optest(testcase): @@ -11,7 +12,7 @@ RESTYPE = testcase[1] args = testcase[2:] - arg_signature = ", ".join(["v%s" % n for n in range(len(args))]) + arg_signature = ", ".join(["a%s" % n for n in range(len(args))]) exec """def lloptest(%s): return llop.%s(%s, %s)""" \ % (arg_signature, llopname, RESTYPE._name, @@ -50,28 +51,63 @@ ("sub", Signed, 1, 3), ("mul", Signed, 2, 3), ("div", Signed, 7, 3), - ("floordiv", Signed, 7, 3), + ("floordiv", Signed, 7, 3), # XXX what about division by zero? ("floordiv", Signed, -7, 3), ("mod", Signed, 9, 4), ("mod", Signed, 9, -4), + ("eq", Bool, 1, 1), + ("eq", Bool, 1, 2), + ("ne", Bool, 1, 1), + ("ne", Bool, 1, 2), + ("lt", Bool, 1, 2), + ("le", Bool, 1, 2), + ("gt", Bool, 1, 2), + ("ge", Bool, 1, 2), +] + +int_tests = general_tests + [ + ("and", Signed, 9, 5), + ("and", Signed, 9, -5), + ("or", Signed, 4, 5), + ("or", Signed, 4, -5), + ("lshift", Signed, 16, 2), + ("rshift", Signed, 16, 2), + ("xor", Signed, 9, 5), + ("xor", Signed, 9, -5), ] def test_intoperations(): - tests = adapt_tests(general_tests, int, Signed, "int") + [ + tests = adapt_tests(int_tests, int, Signed, "int") + [ # binary wraparounds ("int_add", Signed, sys.maxint, 1), ("int_sub", Signed, -sys.maxint-1, 2), ("int_mul", Signed, sys.maxint/2, 3), + ("int_lshift", Signed, sys.maxint, 1), ] for t in tests: yield optest, t def test_uintoperations(): - tests = adapt_tests(general_tests, r_uint, Unsigned, "uint") + [ + tests = adapt_tests(int_tests, r_uint, Unsigned, "uint") + [ # binary wraparounds ("uint_add", Unsigned, r_uint(2*sys.maxint), r_uint(2)), ("uint_sub", Unsigned, r_uint(1), r_uint(3)), ("uint_mul", Unsigned, r_uint(sys.maxint), r_uint(3)), + ("uint_lshift", Unsigned, r_uint(2*sys.maxint), r_uint(1)), + ] + for t in tests: + yield optest, t + +def test_llongoperations(): + tests = adapt_tests(general_tests, r_longlong, SignedLongLong, "llong") + for t in tests: + yield optest, t + +def test_ullongoperations(): + tests = adapt_tests(general_tests, r_ulonglong, UnsignedLongLong, "ullong") + [ + # binary wraparounds + ("ullong_add", UnsignedLongLong, + r_ulonglong(r_ulonglong.MASK), r_ulonglong(10)), ] for t in tests: yield optest, t From nik at codespeak.net Fri Mar 17 14:27:13 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 17 Mar 2006 14:27:13 +0100 (CET) Subject: [pypy-svn] r24517 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060317132713.84912100C8@code0.codespeak.net> Author: nik Date: Fri Mar 17 14:27:01 2006 New Revision: 24517 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/gensqueak.py pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/runtest.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: added implementation and test for bool_not llop. stumbled over the camel_case mess and cleaned that up, camel_case is now defined in and exclusively called from gensqueak.py. also, check uniqueness of variable names as well, since there can be collisions, e.g. between v19 and v1_9 (this one actually happened!). Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Fri Mar 17 14:27:01 2006 @@ -1,11 +1,6 @@ from pypy.objspace.flow.model import Constant, Variable from pypy.rpython.ootypesystem import ootype -def camel_case(identifier): - identifier = identifier.replace(".", "_") - words = identifier.split('_') - return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) - class AbstractCode: pass @@ -13,7 +8,7 @@ class Message(AbstractCode): def __init__(self, name): - self.name = camel_case(name) # XXX Should not use camel_case here + self.name = name self.infix = False if len(name) <= 2 and not name.isalnum(): # Binary infix selector, e.g. "+" @@ -82,7 +77,7 @@ def format_arg(self, arg): """Formats Variables and Constants.""" if isinstance(arg, Variable): - return camel_case(arg.name) + return self.gen.unique_var_name(arg) elif isinstance(arg, Constant): if isinstance(arg.concretetype, ootype.Instance): # XXX fix this Modified: pypy/dist/pypy/translator/squeak/gensqueak.py ============================================================================== --- pypy/dist/pypy/translator/squeak/gensqueak.py (original) +++ pypy/dist/pypy/translator/squeak/gensqueak.py Fri Mar 17 14:27:01 2006 @@ -1,5 +1,4 @@ from pypy.translator.gensupp import NameManager -from pypy.translator.squeak.codeformatter import camel_case from pypy.translator.squeak.node import FunctionNode, ClassNode, SetupNode from pypy.translator.squeak.node import MethodNode, SetterNode, GetterNode try: @@ -91,6 +90,9 @@ return self.unique_name( (INSTANCE, "field", field_name), field_name) + def unique_var_name(self, variable): + return self.unique_name(variable, variable.name) + def unique_name(self, key, basename): # XXX should account for squeak keywords here if self.unique_name_mapping.has_key(key): @@ -101,3 +103,9 @@ self.unique_name_mapping[key] = unique return unique + +def camel_case(identifier): + identifier = identifier.replace(".", "_") + words = identifier.split('_') + return ''.join([words[0]] + [w.capitalize() for w in words[1:]]) + Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Fri Mar 17 14:27:01 2006 @@ -1,7 +1,7 @@ import datetime from pypy.objspace.flow.model import Constant, Variable from pypy.translator.squeak.opformatter import OpFormatter -from pypy.translator.squeak.codeformatter import CodeFormatter, Message, camel_case +from pypy.translator.squeak.codeformatter import CodeFormatter, Message from pypy.translator.squeak.codeformatter import Field, Assignment, CustomVariable from pypy.rpython.ootypesystem.ootype import Instance, ROOT @@ -269,7 +269,7 @@ codef.format(self.INSTANCE), "initializers") fields = self.INSTANCE._allfields() args = [CustomVariable("a%s" % i) for i in range(len(fields))] - message = Message("field_init").with_args(args) + message = Message("fieldInit").with_args(args) yield codef.format(message) for field_name, arg in zip(fields.keys(), args): unique_field = self.gen.unique_field_name(self.INSTANCE, field_name) @@ -306,7 +306,7 @@ field_names = INST._allfields().keys() field_values = [getattr(const.value, f) for f in field_names] new = Message("new").send_to(INST, []) - init_message = Message("field_init").send_to(new, field_values) + init_message = Message("fieldInit").send_to(new, field_values) yield " Constants at: '%s' put: %s." \ % (const_id, codef.format(init_message)) yield "! !" Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Fri Mar 17 14:27:01 2006 @@ -30,6 +30,7 @@ 'runtimenew': 'new', 'classof': 'class', 'same_as': 'yourself', + 'bool_not': 'not', } number_ops = { @@ -80,7 +81,10 @@ if op_method is not None: return op_method(op) else: - name = self.ops.get(op.opname, op.opname) + if not self.ops.has_key(op.opname): + raise NotImplementedError( + "operation not supported: %s" % op.opname) + name = self.ops[op.opname] sent = Message(name).send_to(op.args[0], op.args[1:]) return self.codef.format(sent.assign_to(op.result)) Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Fri Mar 17 14:27:01 2006 @@ -1,7 +1,7 @@ import os import py from pypy.tool.udir import udir -from pypy.translator.squeak.gensqueak import GenSqueak +from pypy.translator.squeak.gensqueak import GenSqueak, camel_case from pypy.translator.translator import TranslationContext from pypy import conftest @@ -67,7 +67,7 @@ return startup_st def _symbol(self, arg_count): - name = self._func.__name__ + name = camel_case(self._func.__name__) if arg_count == 0: return name else: Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Fri Mar 17 14:27:01 2006 @@ -17,10 +17,12 @@ return llop.%s(%s, %s)""" \ % (arg_signature, llopname, RESTYPE._name, arg_signature) + llfunctest(lloptest, args) +def llfunctest(llfunc, args): annotation = [type(a) for a in args] - sqfunc = compile_function(lloptest, annotation) - expected_res = interpret(lloptest, args, policy=LowLevelAnnotatorPolicy()) + sqfunc = compile_function(llfunc, annotation) + expected_res = interpret(llfunc, args, policy=LowLevelAnnotatorPolicy()) res = sqfunc(*args) assert res == str(expected_res).lower() # lowercasing for booleans @@ -112,3 +114,12 @@ for t in tests: yield optest, t +def test_booloperations(): + def bool_not(i): + if i == 1: + j = True + else: + j = False + return llop.bool_not(Bool, j) + llfunctest(bool_not, (1,)) + From arigo at codespeak.net Fri Mar 17 14:35:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 17 Mar 2006 14:35:33 +0100 (CET) Subject: [pypy-svn] r24518 - in pypy/dist/pypy/jit: . test Message-ID: <20060317133533.A5894100CA@code0.codespeak.net> Author: arigo Date: Fri Mar 17 14:35:31 2006 New Revision: 24518 Modified: pypy/dist/pypy/jit/hintcontainer.py pypy/dist/pypy/jit/hintmodel.py pypy/dist/pypy/jit/test/test_hint_annotation.py Log: hintannotator: detect mixing of incompatible virtual container types and fall back by setting a "degenerated" flag on the ContainerDef. The hintrtyper should detect this flag. Modified: pypy/dist/pypy/jit/hintcontainer.py ============================================================================== --- pypy/dist/pypy/jit/hintcontainer.py (original) +++ pypy/dist/pypy/jit/hintcontainer.py Fri Mar 17 14:35:31 2006 @@ -12,6 +12,12 @@ def __init__(self, bookkeeper, TYPE): self.T = TYPE self.bookkeeper = bookkeeper + # if a virtual container "escapes" control in some way, e.g. by + # being unified with a SomeLLAbstractVariable, the ContainerDef + # becomes 'degenerated'. For the hintrtyper, degenerated + # SomeLLAbstractContainers should roughly be equivalent to + # SomeLLAbstractVariables. + self.degenerated = False # hack to try to produce a repr that shows identifications key = (self.__class__, TYPE) weakdict = AbstractContainerDef.__cache.setdefault(key, @@ -47,6 +53,14 @@ hs_c.const = TYPE._defl() return hs_c +def degenerate_item(item, ITEM_TYPE): + if isinstance(ITEM_TYPE, lltype.ContainerType): + hs = item.s_value + assert isinstance(hs, hintmodel.SomeLLAbstractContainer) + hs.contentdef.mark_degenerated() + else: + item.generalize(hintmodel.SomeLLAbstractVariable(ITEM_TYPE)) + # ____________________________________________________________ class FieldValue(ListItem): @@ -99,15 +113,37 @@ return self.fields == other.fields def union(self, other): - # xxx about vparent? assert self.T == other.T for name in self.names: self.fields[name].merge(other.fields[name]) + incompatible = False + if self.vparent is not None: + if other.vparent is not None: + if self.vparent.T != other.vparent.T: + incompatible = True + else: + self.vparent.union(other.vparent) + else: + incompatible = True + elif other.vparent is not None: + incompatible = True + if incompatible or self.degenerated or other.degenerated: + self.mark_degenerated() + other.mark_degenerated() return self def generalize_field(self, name, hs_value): self.fields[name].generalize(hs_value) + def mark_degenerated(self): + if self.degenerated: + return + self.degenerated = True + for name in self.names: + degenerate_item(self.fields[name], self.fieldtype(name)) + if self.vparent is not None: + self.vparent.mark_degenerated() + # ____________________________________________________________ @@ -140,3 +176,7 @@ def generalize_item(self, hs_value): self.arrayitem.generalize(hs_value) + + def mark_degenerated(self): + self.degenerated = True + degenerate_item(self.arrayitem, self.T.OF) Modified: pypy/dist/pypy/jit/hintmodel.py ============================================================================== --- pypy/dist/pypy/jit/hintmodel.py (original) +++ pypy/dist/pypy/jit/hintmodel.py Fri Mar 17 14:35:31 2006 @@ -151,6 +151,14 @@ if hs_flags.const.get('forget', False): XXX # not implemented + def getfield(hs_v1, hs_fieldname): + S = hs_v1.concretetype.TO + FIELD_TYPE = getattr(S, hs_fieldname.const) + return SomeLLAbstractVariable(FIELD_TYPE) + + def setfield(hs_v1, hs_fieldname, hs_value): + pass + class __extend__(SomeLLAbstractConstant): def hint(hs_c1, hs_flags): @@ -366,7 +374,18 @@ class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractContainer)): def union((hs_cont1, hs_cont2)): - return SomeLLAbstractContainer(hs_cont1.contentdef.union(hs_cont2.contentdef)) + contentdef = hs_cont1.contentdef.union(hs_cont2.contentdef) + return SomeLLAbstractContainer(contentdef) + +class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractValue)): + def union((hs_cont1, hs_val2)): + hs_cont1.contentdef.mark_degenerated() + assert hs_cont1.concretetype == hs_val2.concretetype + return SomeLLAbstractVariable(hs_cont1.concretetype) + +class __extend__(pairtype(SomeLLAbstractValue, SomeLLAbstractContainer)): + def union((hs_val1, hs_cont2)): + return pair(hs_cont2, hs_val1).union() class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractConstant)): Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/dist/pypy/jit/test/test_hint_annotation.py Fri Mar 17 14:35:31 2006 @@ -294,6 +294,38 @@ hs_n = ha.binding(g1.getargs()[0]) assert hs_n.origins.keys()[0].fixed +def test_prebuilt_structure(): + S = lltype.GcStruct('S', ('n', lltype.Signed)) + s = lltype.malloc(S) + def ll1(n): + s.n = n + return s.n + hs = hannotate(ll1, [int]) + assert isinstance(hs, SomeLLAbstractVariable) + +def test_merge_substructure(): + S = lltype.GcStruct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) + + def ll_function(flag): + t = lltype.malloc(T) + t.s.n = 3 + s = lltype.malloc(S) + s.n = 4 + if flag: + s = t.s + return s, t + hs = hannotate(ll_function, [bool]) + assert isinstance(hs, SomeLLAbstractContainer) + assert not hs.contentdef.degenerated + assert len(hs.contentdef.fields) == 2 + hs0 = hs.contentdef.fields['item0'].s_value # 's' + assert isinstance(hs0, SomeLLAbstractContainer) + assert hs0.contentdef.degenerated + hs1 = hs.contentdef.fields['item1'].s_value # 't' + assert isinstance(hs1, SomeLLAbstractContainer) + assert hs1.contentdef.degenerated + def test_simple_fixed_call(): def ll_help(cond, x, y): if cond: From ericvrp at codespeak.net Fri Mar 17 14:49:08 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 17 Mar 2006 14:49:08 +0100 (CET) Subject: [pypy-svn] r24519 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060317134908.859C4100CA@code0.codespeak.net> Author: ericvrp Date: Fri Mar 17 14:49:06 2006 New Revision: 24519 Modified: pypy/dist/pypy/translator/llvm/pyllvm/setup.py pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Finally got pyllvm working on Darwin Modified: pypy/dist/pypy/translator/llvm/pyllvm/setup.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/setup.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/setup.py Fri Mar 17 14:49:06 2006 @@ -1,84 +1,44 @@ import autopath import py - +import sys from distutils.core import setup from distutils.extension import Extension -import os -import glob - -# XXX make libdir configurable -#libdir = py.path.local("/usr/local/lib/") -libdir = py.path.local(__file__).dirpath().join("libs") - -# get all the extra objects llvm needs -extra_objects = """ -LLVMX86.o -LLVMSystem.o -LLVMSupport.o -LLVMCore.o -LLVMAsmParser.o -LLVMCodeGen.o -LLVMSelectionDAG.o -LLVMExecutionEngine.o -LLVMJIT.o -LLVMScalarOpts.o -LLVMbzip2.o - -LLVMInterpreter.o -LLVMAnalysis.o -LLVMipo.o -LLVMTransformUtils.o -LLVMipa.o -LLVMDataStructure.o -LLVMTransforms.o -LLVMInstrumentation.o -LLVMBCWriter.o -LLVMBCReader.o -""".split() +prefix = py.path.local.sysfind("llvm-as").dirpath('..').realpath() +incdir = prefix.join('include') +libdir = prefix.join('lib') + +# get all the libraries llvm needs +platform2backend = {'darwin':'PowerPC', 'linux2':'X86'} +llvm_libs = [platform2backend[sys.platform]] + """ +Core AsmParser CodeGen SelectionDAG ExecutionEngine +JIT bzip2 Interpreter DataStructure BCWriter BCReader Target Instrumentation +ipo ipa Transforms System ScalarOpts Analysis TransformUtils Support""".split() + +# figure out if they are a dynamic library or not +extra_llvm_libs, extra_llvm_dynlibs = [], [] +for o in llvm_libs: + if libdir.join("LLVM%s.o" % o).check(): + extra_llvm_libs.append(libdir.join("LLVM%s.o" % o).strpath) + else: + extra_llvm_dynlibs.append("LLVM%s" % o) # globals name = 'pyllvm' sources = ['pyllvm.cpp'] -libraries = ["LLVMTarget"] -include_dirs = ['/opt/projects/llvm-1.6/build/include'] -library_dirs = [str(libdir)] -define_macros = [('_GNU_SOURCE', None), ('__STDC_LIMIT_MACROS', None)] -extra_objects = [str(libdir.join(obj)) for obj in extra_objects] +include_dirs = [incdir.strpath] +library_dirs = [libdir.strpath] +define_macros = [('__STDC_LIMIT_MACROS', None)] #, ('_GNU_SOURCE', None) opts = dict(name=name, sources=sources, - libraries=libraries, + libraries=extra_llvm_dynlibs, include_dirs=include_dirs, library_dirs=library_dirs, define_macros=define_macros, - extra_objects=extra_objects) + extra_objects=extra_llvm_libs) ext_modules = Extension(**opts) # setup module setup(name=name, ext_modules=[ext_modules]) - -# bunch of unused object (at the moment or for x86) -unused_objects = """ -LLVMSkeleton.o -LLVMProfilePaths.o -LLVMCBackend.o -LLVMDebugger.o -profile_rt.o -trace.o -gcsemispace.o -LLVMSparcV8.o -LLVMSparcV9.o -LLVMSparcV9InstrSched.o -LLVMSparcV9LiveVar.o -LLVMSparcV9ModuloSched.o -LLVMSparcV9RegAlloc.o -LLVMPowerPC.o -LLVMAlpha.o -LLVMIA64.o -sample.o -stkr_compiler.o -LLVMTarget.o -""" - Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Fri Mar 17 14:49:06 2006 @@ -1,9 +1,16 @@ import py from pypy.translator.llvm.buildllvm import llvm_is_on_path -py.test.skip("'python setup.py build_ext -i' is not quiet working yet") + if not llvm_is_on_path(): py.test.skip("llvm not found") -from pypy.translator.llvm.pyllvm import pyllvm + +try: + from pypy.translator.llvm.pyllvm import pyllvm +except: + import sys + sys.argv = "setup.py build_ext -i".split() + from pypy.translator.llvm.pyllvm import setup + from pypy.translator.llvm.pyllvm import pyllvm def test_execution_engine(): ee = pyllvm.get_ee() From cfbolz at codespeak.net Fri Mar 17 14:53:55 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 14:53:55 +0100 (CET) Subject: [pypy-svn] r24520 - in pypy/dist/pypy/rpython: . memory/test test Message-ID: <20060317135355.9E541100CA@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 14:53:48 2006 New Revision: 24520 Modified: pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py pypy/dist/pypy/rpython/test/test_llinterp.py Log: use the information provided in lltypesystem/lloperation.py to check whether an operation is expected to raise a certain exception. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Fri Mar 17 14:53:48 2006 @@ -1,6 +1,6 @@ from pypy.objspace.flow.model import FunctionGraph, Constant, Variable, c_last_exception from pypy.rpython.rarithmetic import intmask, r_uint, ovfcheck, r_longlong, r_ulonglong -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype, llmemory, lloperation from pypy.rpython.memory import lladdress from pypy.rpython.ootypesystem import ootype @@ -91,6 +91,20 @@ frame = frame.f_back return roots + def find_exception(self, exc): + assert isinstance(exc, LLException) + import exceptions + klass, inst = exc.args[0], exc.args[1] + # indirect way to invoke fn_pyexcclass2exc, for memory/test/test_llinterpsim + f = self.typer.getexceptiondata().fn_pyexcclass2exc + obj = self.typer.type_system.deref(f) + ll_pyexcclass2exc_graph = obj.graph + for cls in exceptions.__dict__.values(): + if type(cls) is type(Exception): + if self.eval_graph(ll_pyexcclass2exc_graph, [lltype.pyobjectptr(cls)]).typeptr == klass: + return cls + raise ValueError, "couldn't match exception" + # implementations of ops from flow.operation from pypy.objspace.flow.operation import FunctionByName @@ -106,6 +120,7 @@ def checkadr(addr): return lltype.typeOf(addr) == llmemory.Address + class LLFrame(object): def __init__(self, graph, args, llinterpreter, f_back=None): @@ -258,7 +273,18 @@ vals.insert(0, operation.result.concretetype) try: retval = ophandler(*vals) - except LLException: + except LLException, e: + # safety check check that the operation is allowed to raise that + # exception + if operation.opname in lloperation.LL_OPERATIONS: + canraise = lloperation.LL_OPERATIONS[operation.opname].canraise + if Exception not in canraise: + exc = self.llinterpreter.find_exception(e) + for canraiseexc in canraise: + if issubclass(exc, canraiseexc): + break + else: + raise TypeError("the operation %s is not expected to raise %s" % (operation, exc)) self.handle_cleanup(operation, exception=True) raise else: Modified: pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py Fri Mar 17 14:53:48 2006 @@ -11,7 +11,7 @@ from pypy.rpython.memory.lltypesimulation import pyobjectptr from pypy.rpython.memory import gclltype -from pypy.rpython.test.test_llinterp import timelog, gengraph, find_exception +from pypy.rpython.test.test_llinterp import timelog, gengraph def setup_module(mod): mod.logstate = py.log._getstate() @@ -60,7 +60,7 @@ interp, graph = get_interpreter(func, values, view, viewbefore, policy, someobjects) info = py.test.raises(LLException, "interp.eval_graph(graph, values)") - assert find_exception(info.value, interp) is exc, "wrong exception type" + assert interp.find_exception(info.value) is exc, "wrong exception type" #__________________________________________________________________ # tests Modified: pypy/dist/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_llinterp.py (original) +++ pypy/dist/pypy/rpython/test/test_llinterp.py Fri Mar 17 14:53:48 2006 @@ -1,7 +1,7 @@ import py from pypy.rpython.lltypesystem.lltype import typeOf, pyobjectptr, Ptr, PyObject, Void -from pypy.rpython.llinterp import LLInterpreter, LLException,log +from pypy.rpython.llinterp import LLInterpreter, LLException, log from pypy.rpython.rmodel import inputconst from pypy.translator.translator import TranslationContext from pypy.rpython.rlist import * @@ -20,19 +20,6 @@ def teardown_module(mod): py.log._setstate(mod.logstate) -def find_exception(exc, interp): - assert isinstance(exc, LLException) - import exceptions - klass, inst = exc.args[0], exc.args[1] - # indirect way to invoke fn_pyexcclass2exc, for memory/test/test_llinterpsim - f = typer.getexceptiondata().fn_pyexcclass2exc - obj = typer.type_system.deref(f) - ll_pyexcclass2exc_graph = obj.graph - for cls in exceptions.__dict__.values(): - if type(cls) is type(Exception): - if interp.eval_graph(ll_pyexcclass2exc_graph, [pyobjectptr(cls)]).typeptr == klass: - return cls - raise ValueError, "couldn't match exception" def timelog(prefix, call, *args, **kwds): @@ -109,7 +96,7 @@ interp, graph = get_interpreter(func, values, view, viewbefore, policy, someobjects, type_system=type_system) info = py.test.raises(LLException, "interp.eval_graph(graph, values)") - assert find_exception(info.value, interp) is exc, "wrong exception type" + assert interp.find_exception(info.value) is exc, "wrong exception type" #__________________________________________________________________ # tests From nik at codespeak.net Fri Mar 17 15:03:03 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 17 Mar 2006 15:03:03 +0100 (CET) Subject: [pypy-svn] r24521 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060317140303.8D090100C4@code0.codespeak.net> Author: nik Date: Fri Mar 17 15:03:02 2006 New Revision: 24521 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: implement all char and unichar operations for gensqueak. Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Fri Mar 17 15:03:02 2006 @@ -61,7 +61,8 @@ # XXX need to support x_ovf ops } - number_opprefixes = "int", "uint", "llong", "ullong", "float" + number_opprefixes = "int", "uint", "llong", "ullong",\ + "float", "char", "unichar" wrapping_ops = "neg", "invert", "add", "sub", "mul", "lshift" @@ -79,7 +80,7 @@ op, opname_parts[0], "_".join(opname_parts[1:])) op_method = getattr(self, "op_%s" % op.opname, None) if op_method is not None: - return op_method(op) + return self.codef.format(op_method(op)) else: if not self.ops.has_key(op.opname): raise NotImplementedError( @@ -110,7 +111,7 @@ else: receiver = op.args[1] sent_message = Message(message_name).send_to(receiver, op.args[2:]) - return self.codef.format(sent_message.assign_to(op.result)) + return sent_message.assign_to(op.result) def op_oogetfield(self, op): INST = op.args[0].concretetype @@ -123,7 +124,7 @@ else: # Public field access rvalue = Message(field_name).send_to(op.args[0], []) - return self.codef.format(Assignment(op.result, rvalue)) + return Assignment(op.result, rvalue) def op_oosetfield(self, op): # Note that the result variable is never used @@ -132,19 +133,24 @@ field_value = op.args[2] if op.args[0] == self.node.self: # Private field access - return self.codef.format(Assignment(Field(field_name), field_value)) + return Assignment(Field(field_name), field_value) else: # Public field access - setter = Message(field_name).send_to(op.args[0], [field_value]) - return self.codef.format(setter) + return Message(field_name).send_to(op.args[0], [field_value]) def op_oodowncast(self, op): - return self.codef.format(Assignment(op.result, op.args[0])) + return Assignment(op.result, op.args[0]) def op_direct_call(self, op): # XXX how do i get rid of this import? from pypy.translator.squeak.node import FunctionNode function_name = self.gen.unique_func_name(op.args[0].value.graph) msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) - return self.codef.format(msg.assign_to(op.result)) + return msg.assign_to(op.result) + + def op_cast_int_to_char(self, op): + # XXX incomplete + return Assignment(op.result, op.args[0]) + + op_cast_int_to_unichar = op_cast_int_to_char Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Fri Mar 17 15:03:02 2006 @@ -3,7 +3,7 @@ from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Bool +from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Bool, Char, UniChar from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong from pypy.rpython.test.test_llinterp import interpret @@ -123,3 +123,19 @@ return llop.bool_not(Bool, j) llfunctest(bool_not, (1,)) +def test_charoperations(): + for llopname in "eq", "ne", "lt", "gt", "le", "ge": + exec """def lloptest(i1, i2): + char1 = llop.cast_int_to_char(Char, i1) + char2 = llop.cast_int_to_char(Char, i2) + return llop.char_%s(Bool, char1, char2)""" % llopname + yield llfunctest, lloptest, (1, 2) + +def test_unicharoperations(): + for llopname in "eq", "ne": + exec """def lloptest(i1, i2): + char1 = llop.cast_int_to_unichar(UniChar, i1) + char2 = llop.cast_int_to_unichar(UniChar, i2) + return llop.unichar_%s(Bool, char1, char2)""" % llopname + yield llfunctest, lloptest, (1, 2) + From ericvrp at codespeak.net Fri Mar 17 15:15:08 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 17 Mar 2006 15:15:08 +0100 (CET) Subject: [pypy-svn] r24522 - pypy/dist/pypy/translator/llvm/pyllvm Message-ID: <20060317141508.4D3EC100C4@code0.codespeak.net> Author: ericvrp Date: Fri Mar 17 15:15:07 2006 New Revision: 24522 Modified: pypy/dist/pypy/translator/llvm/pyllvm/setup.py Log: Fixes for pyllvm on Linux. Both static and dynamic llvm libs are created on this platform, we pick the dynamic libs because the static ones give unresolved symbols. The library order needed to be changed a little to make things work. Modified: pypy/dist/pypy/translator/llvm/pyllvm/setup.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/setup.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/setup.py Fri Mar 17 15:15:07 2006 @@ -13,15 +13,15 @@ llvm_libs = [platform2backend[sys.platform]] + """ Core AsmParser CodeGen SelectionDAG ExecutionEngine JIT bzip2 Interpreter DataStructure BCWriter BCReader Target Instrumentation -ipo ipa Transforms System ScalarOpts Analysis TransformUtils Support""".split() +ipo ipa Transforms System ScalarOpts TransformUtils Analysis Support""".split() # figure out if they are a dynamic library or not extra_llvm_libs, extra_llvm_dynlibs = [], [] for o in llvm_libs: - if libdir.join("LLVM%s.o" % o).check(): - extra_llvm_libs.append(libdir.join("LLVM%s.o" % o).strpath) - else: + if libdir.join("libLLVM%s.a" % o).check(): extra_llvm_dynlibs.append("LLVM%s" % o) + else: + extra_llvm_libs.append(libdir.join("LLVM%s.o" % o).strpath) # globals name = 'pyllvm' From cfbolz at codespeak.net Fri Mar 17 17:17:46 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 17:17:46 +0100 (CET) Subject: [pypy-svn] r24523 - pypy/dist/pypy/rpython/memory Message-ID: <20060317161746.C6BB1100BD@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 17:17:40 2006 New Revision: 24523 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: attach cleanups only to those operations that are expected to raise Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Fri Mar 17 17:17:40 2006 @@ -1,6 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem.lloperation import llop, LL_OPERATIONS from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, \ c_last_exception, FunctionGraph, Block, Link, checkgraph from pypy.translator.unsimplify import insert_empty_block @@ -11,7 +11,6 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator import sets, os -EXCEPTION_RAISING_OPS = ['direct_call', 'indirect_call'] NEVER_RAISING_OPS = ['gc_protect', 'gc_unprotect'] def var_needsgc(var): @@ -103,8 +102,8 @@ # graph-transforming capabilities of the RTyper instead, as we # seem to run into all the same problems as the ones we already # had to solve there. - num_ops_after_exc_raising = 0 - for op in block.operations: + has_exception_handler = block.exitswitch == c_last_exception + for i, op in enumerate(block.operations): num_ops_after_exc_raising = 0 res = self.replacement_operations(op, livevars) try: @@ -116,9 +115,16 @@ newops.extend(ops) origname = op.opname op = ops[-1-num_ops_after_exc_raising] - # XXX for now we assume that everything can raise - # XXX quick hack to make the protect stuff not add exception handling - if origname not in NEVER_RAISING_OPS and (1 or op.opname in EXCEPTION_RAISING_OPS): + # look into the table of all operations to check whether op is + # expected to raise. if it is not in the table or the last + # operation in a block with exception catching, we assume it can + if (op.opname not in LL_OPERATIONS or + op.opname not in NEVER_RAISING_OPS or + (has_exception_handler and i == len(block.operations) - 1)): + can_raise = True + else: + can_raise = bool(LL_OPERATIONS[op.opname].canraise) + if can_raise: if tuple(livevars) in livevars2cleanup: cleanup_on_exception = livevars2cleanup[tuple(livevars)] else: @@ -128,6 +134,8 @@ cleanup_on_exception = tuple(cleanup_on_exception) livevars2cleanup[tuple(livevars)] = cleanup_on_exception op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception + else: + op.cleanup = None op = ops[-1] if var_needsgc(op.result): if op.opname not in ('direct_call', 'indirect_call') and not var_ispyobj(op.result): From nik at codespeak.net Fri Mar 17 17:27:50 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 17 Mar 2006 17:27:50 +0100 (CET) Subject: [pypy-svn] r24524 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060317162750.4883A100BD@code0.codespeak.net> Author: nik Date: Fri Mar 17 17:27:48 2006 New Revision: 24524 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: support some casts from bool and and chars in gensqueak. Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Fri Mar 17 17:27:48 2006 @@ -85,6 +85,9 @@ arg, "const_%s" % self.format_Instance(arg.value._TYPE)) self.gen.constant_insts[arg] = const_id return "(PyConstants getConstant: '%s')" % const_id + elif arg.concretetype == ootype.Char or arg.concretetype == ootype.UniChar: + # XXX temporary + return str(ord(arg.value)) else: return self.name_constant(arg.value) else: Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Fri Mar 17 17:27:48 2006 @@ -60,7 +60,7 @@ 'xor': 'bitXor', # XXX need to support x_ovf ops } - + number_opprefixes = "int", "uint", "llong", "ullong",\ "float", "char", "unichar" @@ -138,9 +138,11 @@ # Public field access return Message(field_name).send_to(op.args[0], [field_value]) - def op_oodowncast(self, op): + def noop(self, op): return Assignment(op.result, op.args[0]) + op_oodowncast = noop + def op_direct_call(self, op): # XXX how do i get rid of this import? from pypy.translator.squeak.node import FunctionNode @@ -148,6 +150,15 @@ msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) return msg.assign_to(op.result) + def op_cast_bool_to_int(self, op): + msg = Message("ifTrue: [1] ifFalse: [0]") + return msg.send_to(op.args[0], []).assign_to(op.result) + + op_cast_bool_to_uint = op_cast_bool_to_int + + op_cast_char_to_int = noop + op_cast_unichar_to_int = noop + def op_cast_int_to_char(self, op): # XXX incomplete return Assignment(op.result, op.args[0]) Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Fri Mar 17 17:27:48 2006 @@ -139,3 +139,25 @@ return llop.unichar_%s(Bool, char1, char2)""" % llopname yield llfunctest, lloptest, (1, 2) +def test_cast_bool(): + tests = ("int", Signed), ("uint", Unsigned) # XXX missing float + for target_name, target_type in tests: + exec """def lloptest(i): + b = llop.int_is_true(Bool, i) + return llop.cast_bool_to_%s(%s, b)""" \ + % (target_name, target_type._name) + yield llfunctest, lloptest, (3,) + yield llfunctest, lloptest, (0,) + +def test_cast_char(): + tests = ("char", str), ("unichar", unicode) + for from_name, from_type in tests: + exec """def lloptest(i): + if i == 1: + c = %s + else: + c = %s + return llop.cast_%s_to_int(Signed, c)""" \ + % (repr(from_type("a")), repr(from_type("b")), from_name) + yield llfunctest, lloptest, (1,) + From cfbolz at codespeak.net Fri Mar 17 18:02:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 18:02:37 +0100 (CET) Subject: [pypy-svn] r24525 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20060317170237.4756F100BD@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 18:02:25 2006 New Revision: 24525 Added: pypy/dist/pypy/translator/backendopt/canraise.py pypy/dist/pypy/translator/backendopt/test/test_canraise.py Log: functions to find out whether a function can raise Added: pypy/dist/pypy/translator/backendopt/canraise.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/backendopt/canraise.py Fri Mar 17 18:02:25 2006 @@ -0,0 +1,55 @@ +from pypy.translator.simplify import get_graph +from pypy.rpython.lltypesystem.lloperation import llop, LL_OPERATIONS +from pypy.rpython.lltypesystem import lltype + +class ExceptionInfo(object): + def __init__(self, translator, can_raise, cannot_raise=None): + self.can_raise = can_raise + self.cannot_raise = cannot_raise + self.translator = translator + + def exception_match(self, etype): + pass + +class RaiseAnalyzer(object): + def __init__(self, translator): + self.translator = translator + self.call_can_raise = {} + + def can_raise(self, op, seen=None): + if op.opname == "direct_call": + graph = get_graph(op.args[0], self.translator) + print "graph", graph + if graph is None: + return True + return self.direct_call_can_raise(graph, seen) + elif op.opname == "indirect_call": + return self.indirect_call_can_raise(op.args[-1].value, seen) + else: + return bool(LL_OPERATIONS[op.opname].canraise) + + def direct_call_can_raise(self, graph, seen=None): + if graph in self.call_can_raise: + return self.call_can_raise[graph] + if seen is None: + seen = {} + if graph in seen: + self.call_can_raise[graph] = False + return False + else: + seen[graph] = True + for block in graph.iterblocks(): + if block is graph.exceptblock: + return True # the except block is reached + for op in block.operations: + if self.can_raise(op, seen): + self.call_can_raise[graph] = True + return True + self.call_can_raise[graph] = False + return False + + def indirect_call_can_raise(self, graphs, seen=None): + for graph in graphs: + if self.direct_call_can_raise(graph, seen): + return True + return False Added: pypy/dist/pypy/translator/backendopt/test/test_canraise.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/backendopt/test/test_canraise.py Fri Mar 17 18:02:25 2006 @@ -0,0 +1,63 @@ +from pypy.translator.translator import TranslationContext, graphof +from pypy.translator.backendopt.canraise import RaiseAnalyzer +from pypy.conftest import option + +def translate(func, sig): + t = TranslationContext() + t.buildannotator().build_types(func, sig) + t.buildrtyper().specialize() + if option.view: + t.view() + return t, RaiseAnalyzer(t) + +def test_can_raise_simple(): + def g(x): + return True + + def f(x): + return g(x - 1) + t, ra = translate(f, [int]) + fgraph = graphof(t, f) + result = ra.can_raise(fgraph.startblock.operations[0]) + assert not result + +def test_can_raise_recursive(): + def g(x): + return f(x) + + def f(x): + if x: + return g(x - 1) + return 1 + t, ra = translate(f, [int]) + ggraph = graphof(t, g) + result = ra.can_raise(ggraph.startblock.operations[1]) + assert not result # due to stack check every recursive function can raise + +def test_can_raise_exception(): + def g(): + raise ValueError + def f(): + return g() + t, ra = translate(f, []) + fgraph = graphof(t, f) + result = ra.can_raise(fgraph.startblock.operations[0]) + assert result + +def test_indirect_call(): + def g1(): + raise ValueError + def g2(): + return 2 + def f(x): + if x: + g = g1 + else: + g = g2 + return g() + def h(x): + return f(x) + t, ra = translate(h, [int]) + hgraph = graphof(t, h) + result = ra.can_raise(hgraph.startblock.operations[0]) + assert result From cfbolz at codespeak.net Fri Mar 17 18:09:58 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 18:09:58 +0100 (CET) Subject: [pypy-svn] r24526 - pypy/dist/pypy/translator/backendopt/test Message-ID: <20060317170958.6E143100BD@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 18:09:57 2006 New Revision: 24526 Modified: pypy/dist/pypy/translator/backendopt/test/test_canraise.py Log: test that an external function is assumed to always raise Modified: pypy/dist/pypy/translator/backendopt/test/test_canraise.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_canraise.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_canraise.py Fri Mar 17 18:09:57 2006 @@ -32,7 +32,7 @@ t, ra = translate(f, [int]) ggraph = graphof(t, g) result = ra.can_raise(ggraph.startblock.operations[1]) - assert not result # due to stack check every recursive function can raise + assert result # due to stack check every recursive function can raise def test_can_raise_exception(): def g(): @@ -61,3 +61,12 @@ hgraph = graphof(t, h) result = ra.can_raise(hgraph.startblock.operations[0]) assert result + +def test_external(): + import os.path + def f(x): + return os.path.isdir(str(x)) + t, ra = translate(f, [int]) + fgraph = graphof(t, f) + result = ra.can_raise(fgraph.startblock.operations[0]) + assert result From cfbolz at codespeak.net Fri Mar 17 18:23:08 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 18:23:08 +0100 (CET) Subject: [pypy-svn] r24527 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20060317172308.C8C23100BD@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 18:22:57 2006 New Revision: 24527 Modified: pypy/dist/pypy/translator/backendopt/canraise.py pypy/dist/pypy/translator/backendopt/test/test_canraise.py Log: make the case work where indirect_call does not have the called graphs attached Modified: pypy/dist/pypy/translator/backendopt/canraise.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/canraise.py (original) +++ pypy/dist/pypy/translator/backendopt/canraise.py Fri Mar 17 18:22:57 2006 @@ -49,6 +49,8 @@ return False def indirect_call_can_raise(self, graphs, seen=None): + if graphs is None: + return True for graph in graphs: if self.direct_call_can_raise(graph, seen): return True Modified: pypy/dist/pypy/translator/backendopt/test/test_canraise.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_canraise.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_canraise.py Fri Mar 17 18:22:57 2006 @@ -70,3 +70,22 @@ fgraph = graphof(t, f) result = ra.can_raise(fgraph.startblock.operations[0]) assert result + +def test_instantiate(): + from pypy.rpython.objectmodel import instantiate + class A: + pass + class B(A): + pass + def g(x): + if x: + C = A + else: + C = B + a = instantiate(C) + def f(x): + return g(x) + t, ra = translate(f, [int]) + fgraph = graphof(t, f) + result = ra.can_raise(fgraph.startblock.operations[0]) + assert result From cfbolz at codespeak.net Fri Mar 17 18:23:32 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 17 Mar 2006 18:23:32 +0100 (CET) Subject: [pypy-svn] r24528 - pypy/dist/pypy/translator/backendopt/test Message-ID: <20060317172332.510D6100C1@code0.codespeak.net> Author: cfbolz Date: Fri Mar 17 18:23:31 2006 New Revision: 24528 Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py Log: add t.view if --view is given Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_malloc.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_malloc.py Fri Mar 17 18:23:31 2006 @@ -5,6 +5,7 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.objspace.flow.model import checkgraph, flatten, Block from pypy.rpython.llinterp import LLInterpreter +from pypy.conftest import option def check_malloc_removed(graph): checkgraph(graph) @@ -24,7 +25,11 @@ t.buildannotator().build_types(fn, signature) t.buildrtyper().specialize() graph = graphof(t, fn) + if option.view: + t.view() remove_simple_mallocs(graph) + if option.view: + t.view() if must_be_removed: check_malloc_removed(graph) interp = LLInterpreter(t.rtyper) From auc at codespeak.net Fri Mar 17 18:37:51 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 17 Mar 2006 18:37:51 +0100 (CET) Subject: [pypy-svn] r24529 - pypy/dist/demo Message-ID: <20060317173751.99CE7100BD@code0.codespeak.net> Author: auc Date: Fri Mar 17 18:37:45 2006 New Revision: 24529 Modified: pypy/dist/demo/producerconsumer.py Log: lazy version of producer consummer Modified: pypy/dist/demo/producerconsumer.py ============================================================================== --- pypy/dist/demo/producerconsumer.py (original) +++ pypy/dist/demo/producerconsumer.py Fri Mar 17 18:37:45 2006 @@ -21,6 +21,7 @@ return sum(Tail, head + a) return a +print "eager producer consummer" print "before" X = newvar() S = newvar() @@ -29,3 +30,34 @@ print "after" print S + + +def lgenerate(n, L): + """wait-needed version of generate""" + print "generator waits on L being needed" + wait_needed(L) + Tail = newvar() + L == (n, Tail) + print "generator bound L to", L + lgenerate(n+1, Tail) + +def lsum(L, a, limit): + """this version of sum controls the generator""" + print "sum", a + if limit > 0: + Head, Tail = newvar(), newvar() + print "sum waiting on L" + Head, Tail = L # or L = (Head, Tail) ... ? + return lsum(Tail, a+Head, limit-1) + else: + return a + +print "lazy producer consummer" +print "before" +Y = newvar() +T = newvar() +uthread(lgenerate, 0, Y) +T == uthread(lsum, Y, 0, 10) +print "after" + +print T From auc at codespeak.net Fri Mar 17 18:38:36 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 17 Mar 2006 18:38:36 +0100 (CET) Subject: [pypy-svn] r24530 - pypy/dist/pypy/objspace Message-ID: <20060317173836.01728100BD@code0.codespeak.net> Author: auc Date: Fri Mar 17 18:38:35 2006 New Revision: 24530 Modified: pypy/dist/pypy/objspace/logic.py Log: attempt at wait_needed Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Fri Mar 17 18:38:35 2006 @@ -25,6 +25,7 @@ def __init__(self): self.runnable_uthreads = {} self.uthreads_blocked_on = {} + self.uthreads_blocked_byneed = {} def pop_runnable_thread(self): # umpf, no popitem in RPython @@ -61,6 +62,25 @@ del self.uthreads_blocked_on[w_var] return blocked + def add_to_blocked_byneed(self, w_var, uthread): + print " adding", uthread, "to byneed on", w_var + if w_var in self.uthreads_blocked_byneed: + blocked = self.uthreads_blocked_byneed[w_var] + else: + blocked = [] + self.uthreads_blocked_byneed[w_var] = blocked + blocked.append(uthread) + + def pop_blocked_byneed_on(self, w_var): + if w_var not in self.uthreads_blocked_byneed: + print " there was nobody to remove for", w_var + return [] + blocked = self.uthreads_blocked_byneed[w_var] + del self.uthreads_blocked_byneed[w_var] + print " removing", blocked, "from byneed on", w_var + return blocked + + schedule_state = ScheduleState() class Thunk(AbstractThunk): @@ -134,6 +154,7 @@ class W_Var(baseobjspace.W_Root, object): def __init__(w_self): w_self.w_bound_to = None + w_self.w_needed = False def find_last_var_in_chain(w_var): w_curr = w_var @@ -157,13 +178,21 @@ raise OperationError(space.w_RuntimeError, space.wrap("trying to perform an operation on an unbound variable")) else: + # notify wait_needed clients, give them a chance to run + w_self.w_needed = True + need_waiters = schedule_state.pop_blocked_byneed_on(w_self) + for waiter in need_waiters: + schedule_state.add_to_runnable(waiter) + # set curr thread to blocked, switch to runnable thread current = get_current_coroutine() schedule_state.add_to_blocked(w_last, current) while schedule_state.have_runnable_threads(): next_coro = schedule_state.pop_runnable_thread() if next_coro.is_alive(): + print " waiter is switching" next_coro.switch() - # there is a value here now + print " waiter is back" + # hope there is a value here now break else: raise OperationError(space.w_RuntimeError, @@ -182,6 +211,42 @@ return w_obj app_wait = gateway.interp2app(wait) +def wait_needed(space, w_self): + while 1: + if not isinstance(w_self, W_Var): + raise OperationError(space.w_RuntimeError, + space.wrap("wait_needed operates only on logic variables")) + w_last = find_last_var_in_chain(w_self) + w_obj = w_last.w_bound_to + if w_obj is None: + if w_self.w_needed: + break # we're done + # XXX here we would have to FOO the current thread + if not have_uthreads(): + raise OperationError(space.w_RuntimeError, + space.wrap("oh please oh FIXME !")) + else: + # add current thread to blocked byneed and switch + current = get_current_coroutine() + schedule_state.add_to_blocked_byneed(w_self, current) + while schedule_state.have_runnable_threads(): + next_coro = schedule_state.pop_runnable_thread() + if next_coro.is_alive(): + print " byneed is switching" + next_coro.switch() + print " byneed is back" + # there might be some need right now + break + else: + raise OperationError(space.w_RuntimeError, + space.wrap("blocked on need, but no uthread that can wait")) + + else: + raise OperationError(space.w_RuntimeError, + space.wrap("wait_needed only supported on unbound variables")) +app_wait_needed = gateway.interp2app(wait_needed) + + def newvar(space): return W_Var() app_newvar = gateway.interp2app(newvar) @@ -367,4 +432,6 @@ space.wrap(app_uthread)) space.setitem(space.builtin.w_dict, space.wrap('wait'), space.wrap(app_wait)) + space.setitem(space.builtin.w_dict, space.wrap('wait_needed'), + space.wrap(app_wait_needed)) return space From auc at codespeak.net Fri Mar 17 18:44:56 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 17 Mar 2006 18:44:56 +0100 (CET) Subject: [pypy-svn] r24531 - pypy/dist/demo Message-ID: <20060317174456.BE3C4100BD@code0.codespeak.net> Author: auc Date: Fri Mar 17 18:44:50 2006 New Revision: 24531 Modified: pypy/dist/demo/producerconsumer.py Log: hmm ... Modified: pypy/dist/demo/producerconsumer.py ============================================================================== --- pypy/dist/demo/producerconsumer.py (original) +++ pypy/dist/demo/producerconsumer.py Fri Mar 17 18:44:50 2006 @@ -47,7 +47,7 @@ if limit > 0: Head, Tail = newvar(), newvar() print "sum waiting on L" - Head, Tail = L # or L = (Head, Tail) ... ? + L == (Head, Tail) # or Head, Tail == L ? return lsum(Tail, a+Head, limit-1) else: return a From arigo at codespeak.net Fri Mar 17 23:17:00 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 17 Mar 2006 23:17:00 +0100 (CET) Subject: [pypy-svn] r24532 - in pypy/dist/pypy/doc: . discussion weekly Message-ID: <20060317221700.4A9EB100D2@code0.codespeak.net> Author: arigo Date: Fri Mar 17 23:16:58 2006 New Revision: 24532 Added: pypy/dist/pypy/doc/jit.txt Modified: pypy/dist/pypy/doc/discussion/draft-jit-ideas.txt pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: Some notes about the current status of the JIT. Modified: pypy/dist/pypy/doc/discussion/draft-jit-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/discussion/draft-jit-ideas.txt (original) +++ pypy/dist/pypy/doc/discussion/draft-jit-ideas.txt Fri Mar 17 23:16:58 2006 @@ -10,13 +10,13 @@ bytecode language, as an example and for testing. The goal is to turn that interpreter into a JIT. -2. MOSTLY DONE (jit/llabstractinterp.py): Write code that takes LL +2. DONE (jit/llabstractinterp.py): Write code that takes LL graphs and "specializes" them, by making a variable constant and propagating it. 3. DONE (jit/test/test_jit_tl.py): Think more about how to plug 1 into 2 :-) -4. Refactor 2 to use `Functions/operations to generate code`_ +4. DONE Refactor 2 to use `Functions/operations to generate code`_ 5. Think about `how to do at run-time what llabstractinterp does statically`_ Added: pypy/dist/pypy/doc/jit.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/jit.txt Fri Mar 17 23:16:58 2006 @@ -0,0 +1,109 @@ +=================================== +PyPy - Just-In-Time Specialization +=================================== + + +Warning: These are just a few notes quickly thrown together, to be +clarified and expanded. + + +Draft +========================= + +Introduction +------------ + +Our current "state of the art" in the area is represented by the test +``pypy.jit.test.test_hint_timeshift.test_arith_plus_minus()``. It is a +really tiny interpreter which gets turned into a compiler. Here is its +complete source:: + + def ll_plus_minus(encoded_insn, nb_insn, x, y): + acc = x + pc = 0 + while pc < nb_insn: + op = (encoded_insn >> (pc*4)) & 0xF + op = hint(op, concrete=True) # <----- + if op == 0xA: + acc += y + elif op == 0x5: + acc -= y + pc += 1 + return acc + +This interpreter goes via several transformations which you can follow +in Pygame:: + + py.test test_hint_timeshift.py -k test_arith_plus_minus --view + +What this does is turning (the graph of) the above interpreter into (the +graph of) a compiler. This compiler takes a user program as input -- +i.e. an ``encoded_insn`` and ``nb_insn`` -- and produces as output a new +graph, which is the compiled version of the user program. The new +output graph is called the *residual* graph. It takes ``x`` and ``y`` +as input. + +This generated compiler is not "just-in-time" in any sense. It is a +regular compiler, for now. + +Hint-annotator +-------------- + +Let's follow how the interpreter is turned into a compiler. First, the +source of the interpreter is turned into low-level graphs in the usual +way (it is actually already a low-level function). This low-level graph +goes then through a pass called the "hint-annotator", whose goal is to +give colors -- red, green and blue -- to each variable in the graph. +The color represents the "time" at which the value of a variable is +expected to be known, when the interpreter works as a compiler. In the +above example, variables like ``pc`` and ``encoded_insn`` need to be +known to the compiler -- otherwise, it wouldn't even know which program +it must compile. These variables need to be *green*. Variables like +``x`` and ``acc``, on the other hand, are expected to appear in the +residual graph; they need to be *red*. + +The color of each variable is derived based on the hint (see the +``<-----`` line in the source): the hint() forces ``op`` to be a green +variable, along with any *previous* variable that is essential to +compute the value of ``op``. The hint-annotator computes dependencies +and back-propagates "greenness" from hint() calls. + +The hint-annotator is implemented on top of the normal annotator; it's +in hintannotator.py, hintmodel.py, hintbookkeeper.py, hintcontainer.py +and hintvlist.py. The latter two files are concerned about the *blue* +variables, which are variable that contain pointers to structures of a +mixed kind: structures which are themselves -- as containers -- known to +the compiler, i.e. green, but whose fields may not all be known to the +compiler. There is no blue variable in the code above, but the stack of +a stack-based interpreter is an example: the "shape" of the stack is +known to the compiler when compiling any bytecode position, but the +actual run-time values in the stack are not. The hint-annotator can now +handle many cases of blue structures and arrays. For low-level +structures and arrays that actually correspond to RPython lists, +hintvlist.py recognize the RPython-level operations and handles them +directly -- this avoids problems with low-level details like +over-allocation, which causes several identical RPython lists to look +different when represented as low-level structs and arrays. + +Hint-RTyper +----------- + +Once the graph has been colored, enters the hint-rtyper. This tool -- +again loosely based on the normal RTyper -- transforms the colored +low-level graphs into the graphs of the compiler. Broadly speaking, +this is done by transforming operations annotated with red variables +into operations that will generate the original operation. Indeed, red +variables are the variables whose run-time content is unknown to the +compiler. So for example, if the arguments of an ``int_add`` have been +annotated as red, it means that the real value of these variables will +not be known to the compiler; when the compiler actually runs, all it +can do is generate a new ``int_add`` operation into the residual graph. + +In the example above, only ``acc += y`` and ``acc -= y`` are annotated +with red arguments. After hint-rtyping, the ll_plus_minus() graph -- +which is now the graph of a compiler -- is mostly unchanged except for +these two operations, which are replaced by a few operations which call +helpers; when the graph of the now-compiler is running, these helpers +will produce new ``int_add`` and ``int_sub`` operations. + +(Extra merging/bookkeeping blocks are actually inserted; XXX explain...) Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Fri Mar 17 23:16:58 2006 @@ -28,11 +28,11 @@ The Logic Sprint ================ -Last week there was a PyPy-sprint at the UCL in Louvain-la-Neuve. It's main +Last week there was a PyPy-sprint at the UCL in Louvain-la-Neuve. Its main topic was logic and constraint programming in PyPy. Two of the sprint days were devoted to discussions with some researchers at the UCL who are heavily involved with the Oz programming language. The discussions were fruitful and -very stimulating. For more details see the `logic sprint report'_ +very stimulating. For more details see the `logic sprint report`_ The Logic Object Space ----------------------- @@ -55,7 +55,7 @@ This required quite a bit of work and first we refactored the way the existing two garbage collectors (reference counting and using the Boehm -collector) are implemented in the C backend. Before they were +collector) are implemented in the C backend. Before, they were implemented by inserting C code into appropriate places in the generated code using string formatting. This had several disadvantages: %-formatting C code is obviously not helpful for other backends, and it @@ -76,3 +76,31 @@ Python code that manipulates memory addresses directly is hard on the brain... we need to get back to being able to run everything on the memory simulator. + +JIT Status +========== + +The JIT did not progress much recently. Nevertheless, it seems useful +to try to give an overview of the current situation and where we are +going next. + +Our current "state of the art" in the area is represented by +``pypy.jit.test.test_hint_timeshift.test_arith_plus_minus()``. It is a +really tiny interpreter which gets turned into a compiler. +There is a very draftish description of what is going on in: + + http://codespeak.net/pypy/dist/pypy/doc/jit.html + +Current areas of work: + +* the hint-rtyping actually produces a lot of bookkeeping code; we will + have to reduce this amount in the future. More worryingly, it doesn't + handle calls at all at the moment. We need to rethink and document + how exactly the code the hint-rtyper produces should look like before + we can start working in this direction. + +* in the last few days, Samuele and Arre worked on virtual structures + (blue variables) for the hint-rtyper. Together with Armin they fixed + some remaining bugs in the hint-annotator. Hint-rtyper support is + still very preliminary and already hitting some head-scratching + questions. From tismer at codespeak.net Sat Mar 18 00:43:03 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 18 Mar 2006 00:43:03 +0100 (CET) Subject: [pypy-svn] r24533 - pypy/dist/pypy/rpython/rctypes Message-ID: <20060317234303.286CC100D2@code0.codespeak.net> Author: tismer Date: Sat Mar 18 00:42:55 2006 New Revision: 24533 Modified: pypy/dist/pypy/rpython/rctypes/rprimitive.py (props changed) Log: can people please do the eolstyle:native alone? From tismer at codespeak.net Sat Mar 18 03:23:35 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 18 Mar 2006 03:23:35 +0100 (CET) Subject: [pypy-svn] r24534 - in pypy/dist/pypy/rpython/memory: . test Message-ID: <20060318022335.D0B2E100D3@code0.codespeak.net> Author: tismer Date: Sat Mar 18 03:23:13 2006 New Revision: 24534 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: fixed exception filtering to handle protect/unprotect correctly. Added a test that ensures this. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 18 03:23:13 2006 @@ -103,9 +103,9 @@ # seem to run into all the same problems as the ones we already # had to solve there. has_exception_handler = block.exitswitch == c_last_exception - for i, op in enumerate(block.operations): + for i, origop in enumerate(block.operations): num_ops_after_exc_raising = 0 - res = self.replacement_operations(op, livevars) + res = self.replacement_operations(origop, livevars) try: ops, cleanup_before_exception = res except ValueError: @@ -113,17 +113,16 @@ if not ops: continue # may happen when we eat gc_protect/gc_unprotect. newops.extend(ops) - origname = op.opname op = ops[-1-num_ops_after_exc_raising] # look into the table of all operations to check whether op is # expected to raise. if it is not in the table or the last # operation in a block with exception catching, we assume it can if (op.opname not in LL_OPERATIONS or - op.opname not in NEVER_RAISING_OPS or (has_exception_handler and i == len(block.operations) - 1)): can_raise = True else: - can_raise = bool(LL_OPERATIONS[op.opname].canraise) + can_raise = (LL_OPERATIONS[op.opname].canraise and + origop.opname not in NEVER_RAISING_OPS) if can_raise: if tuple(livevars) in livevars2cleanup: cleanup_on_exception = livevars2cleanup[tuple(livevars)] Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Sat Mar 18 03:23:13 2006 @@ -217,16 +217,19 @@ pop_count += 1 assert push_count == 0 and pop_count == 1 -def test_protect_unprotect(): - def protect(obj): RaiseNameError - def unprotect(obj): RaiseNameError - def rtype_protect(hop): hop.genop('gc_protect', [hop.inputargs(hop.args_r[0])[0]]) - def rtype_unprotect(hop): hop.genop('gc_unprotect', [hop.inputargs(hop.args_r[0])[0]]) - extregistry.register_value(protect, - compute_result_annotation=lambda *args: None, specialize_call=rtype_protect) - extregistry.register_value(unprotect, - compute_result_annotation=lambda *args: None, specialize_call=rtype_unprotect) +# ____________________________________________________________________ +# testing the protection magic + +def protect(obj): RaiseNameError +def unprotect(obj): RaiseNameError +def rtype_protect(hop): hop.genop('gc_protect', [hop.inputargs(hop.args_r[0])[0]]) +def rtype_unprotect(hop): hop.genop('gc_unprotect', [hop.inputargs(hop.args_r[0])[0]]) +extregistry.register_value(protect, + compute_result_annotation=lambda *args: None, specialize_call=rtype_protect) +extregistry.register_value(unprotect, + compute_result_annotation=lambda *args: None, specialize_call=rtype_unprotect) +def test_protect_unprotect(): def p(): protect('this is an object') def u(): unprotect('this is an object') @@ -239,7 +242,21 @@ t, transformer = rtype_and_transform(f, [], gc, check=False) ops = getops(graphof(t, f)) assert len(ops.get('direct_call', [])) == ex - + +def test_protect_unprotect_no_exception_block(): + def p(): protect('this is an object') + def u(): unprotect('this is an object') + + gc = gctransform.RefcountingGCTransformer + for f in p, u: + t, transformer = rtype_and_transform(f, [], gc, check=False) + has_cleanup = False + ops = getops(graphof(t, f)) + for op in ops.get('direct_call', []): + assert not op.cleanup + +# end of protection tests + def test_except_block(): S = lltype.GcStruct("S", ('x', lltype.Signed)) def f(a, n): From tismer at codespeak.net Sat Mar 18 07:59:04 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 18 Mar 2006 07:59:04 +0100 (CET) Subject: [pypy-svn] r24536 - pypy/dist/pypy/translator/goal Message-ID: <20060318065904.92A57100D3@code0.codespeak.net> Author: tismer Date: Sat Mar 18 07:59:01 2006 New Revision: 24536 Modified: pypy/dist/pypy/translator/goal/bench-windows.py Log: small correction to sorting Modified: pypy/dist/pypy/translator/goal/bench-windows.py ============================================================================== --- pypy/dist/pypy/translator/goal/bench-windows.py (original) +++ pypy/dist/pypy/translator/goal/bench-windows.py Sat Mar 18 07:59:01 2006 @@ -171,11 +171,11 @@ res = [ (stone / rich, exe, size, rich, stone) for rich, stone, exe, mtime, size in resdic.values()] version, size = run_version_size() - res.append( (1.0, 'python %s' % version, size, ref_rich, ref_stone) ) + res.append( (ref_stone/ref_rich, 'python %s' % version, size, ref_rich, ref_stone) ) res.sort() print HEADLINE for speed2, exe, size, rich, stone in res: - if speed2 <= 1.0: + if speed2 <= ref_stone/ref_rich: print FMT % (exe, rich, rich / ref_rich, stone, ref_stone / stone, size / float(1024 * 1024)) else: From nik at codespeak.net Sat Mar 18 16:03:00 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Sat, 18 Mar 2006 16:03:00 +0100 (CET) Subject: [pypy-svn] r24538 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060318150300.442F0100BE@code0.codespeak.net> Author: nik Date: Sat Mar 18 16:02:58 2006 New Revision: 24538 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: implement various casts for ints, all as noops. Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Sat Mar 18 16:02:58 2006 @@ -159,9 +159,9 @@ op_cast_char_to_int = noop op_cast_unichar_to_int = noop - def op_cast_int_to_char(self, op): - # XXX incomplete - return Assignment(op.result, op.args[0]) - - op_cast_int_to_unichar = op_cast_int_to_char + op_cast_int_to_char = noop + op_cast_int_to_unichar = noop + op_cast_int_to_uint = noop + op_cast_int_to_longlong = noop + # XXX to_float missing Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Sat Mar 18 16:02:58 2006 @@ -20,11 +20,17 @@ llfunctest(lloptest, args) def llfunctest(llfunc, args): + expected_res = llinterpret(llfunc, args) + res = sqinterpret(llfunc, args) + assert res == str(expected_res).lower() # lowercasing for booleans + +def sqinterpret(llfunc, args): annotation = [type(a) for a in args] sqfunc = compile_function(llfunc, annotation) - expected_res = interpret(llfunc, args, policy=LowLevelAnnotatorPolicy()) - res = sqfunc(*args) - assert res == str(expected_res).lower() # lowercasing for booleans + return sqfunc(*args) + +def llinterpret(llfunc, args): + return interpret(llfunc, args, policy=LowLevelAnnotatorPolicy()) def adapt_tests(tests, type, RESTYPE, prefix): adapted = [] @@ -161,3 +167,17 @@ % (repr(from_type("a")), repr(from_type("b")), from_name) yield llfunctest, lloptest, (1,) +def test_cast_int(): + tests = [("char", Char), ("unichar", UniChar), + ("longlong", SignedLongLong), ("uint", Unsigned)] + for target_name, target_type in tests: + exec """def lloptest(i): + return llop.cast_int_to_%s(%s, i)""" \ + % (target_name, target_type._name) + args = (2,) + expected_res = llinterpret(lloptest, args) + res = int(sqinterpret(lloptest, args)) + if isinstance(expected_res, (str, unicode)): + res = chr(res) + assert expected_res == res + From cfbolz at codespeak.net Sat Mar 18 19:14:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 18 Mar 2006 19:14:30 +0100 (CET) Subject: [pypy-svn] r24539 - in pypy/dist/pypy/rpython/memory: . test Message-ID: <20060318181430.40F70100B9@code0.codespeak.net> Author: cfbolz Date: Sat Mar 18 19:14:28 2006 New Revision: 24539 Modified: pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/rpython/memory/support.py pypy/dist/pypy/rpython/memory/test/test_gc.py pypy/dist/pypy/rpython/memory/test/test_gctransform.py pypy/dist/pypy/rpython/memory/test/test_support.py Log: make the linked list implementation less braindead: don't allocate a cell of 8 byte for every append. use bigger chunks and also reuse them. This made some changes necessary: Fix the deferred refcounting, because it inspected the linked list directly in a non-valid way. Reset the FreeList in some tests, because the annotator tries to make a pbc out of it, which is a bad idea, since it contains non-NULL address constants. Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Sat Mar 18 19:14:28 2006 @@ -387,15 +387,15 @@ else: self.collecting = True roots = self.get_roots() - curr = roots.first - while 1: - root = curr.address[1] + roots_copy = AddressLinkedList() + curr = roots.pop() + while curr != NULL: ## print "root", root, root.address[0] ## assert self.refcount(root.address[0]) >= 0, "refcount negative" - self.incref(root.address[0]) - if curr.address[0] == NULL: - break - curr = curr.address[0] + self.incref(curr.address[0]) + roots_copy.append(curr) + curr = roots.pop() + roots = roots_copy dealloc_list = AddressLinkedList() self.length_zero_ref_counts = 0 while 1: Modified: pypy/dist/pypy/rpython/memory/support.py ============================================================================== --- pypy/dist/pypy/rpython/memory/support.py (original) +++ pypy/dist/pypy/rpython/memory/support.py Sat Mar 18 19:14:28 2006 @@ -5,31 +5,59 @@ INT_SIZE = sizeof(lltype.Signed) +CHUNK_SIZE = 30 + +class FreeList(object): + _alloc_flavor_ = "raw" + + def __init__(self, size): + self.free_list = NULL + self.size = size + + def get(self): + if self.free_list == NULL: + return raw_malloc(self.size * INT_SIZE) + result = self.free_list + self.free_list = result.address[0] + return result + + def put(self, chunk): + chunk.address[0] = self.free_list + self.free_list = chunk + class AddressLinkedList(object): _alloc_flavor_ = "raw" + + unused_chunks = FreeList(CHUNK_SIZE + 2) + def __init__(self): - self.first = NULL - self.last = NULL + self.chunk = NULL def append(self, addr): if addr == NULL: return - new = raw_malloc(2 * INT_SIZE) - if self.first == NULL: - self.first = new - else: - self.last.address[0] = new - self.last = new - new.address[0] = NULL - new.address[1] = addr + if self.chunk == NULL or self.chunk.signed[1] == CHUNK_SIZE: + new = AddressLinkedList.unused_chunks.get() + new.address[0] = self.chunk + new.signed[1] = 0 + self.chunk = new + used_chunks = self.chunk.signed[1] + self.chunk.signed[1] += 1 + self.chunk.address[used_chunks + 2] = addr def pop(self): - if self.first == NULL: - return NULL - result = self.first.address[1] - next = self.first.address[0] - raw_free(self.first) - self.first = next + used_chunks = self.chunk.signed[1] + if used_chunks == 0: + old = self.chunk + previous = old.address[0] + if previous == NULL: + return NULL + self.chunk = previous + AddressLinkedList.unused_chunks.put(old) + used_chunks = self.chunk.signed[1] + result = self.chunk.address[used_chunks + 1] + self.chunk.address[used_chunks + 1] = NULL + self.chunk.signed[1] = used_chunks - 1 return result def free(self): Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gc.py Sat Mar 18 19:14:28 2006 @@ -6,7 +6,7 @@ from pypy.rpython.rtyper import RPythonTyper from pypy.rpython.memory.gc import GCError, MarkSweepGC, SemiSpaceGC from pypy.rpython.memory.gc import DeferredRefcountingGC, DummyGC -from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE +from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE, CHUNK_SIZE, FreeList from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL from pypy.rpython.memory.simulator import MemorySimulatorError from pypy.rpython.memory import gclltype @@ -97,6 +97,7 @@ class TestMarkSweepGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): + AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp def teardown_class(cls): @@ -111,6 +112,7 @@ class TestSemiSpaceGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): + AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = SemiSpaceGC @@ -130,6 +132,7 @@ class TestDeferredRefcountingGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): + AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = DeferredRefcountingGC @@ -148,6 +151,7 @@ class TestDummyGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): + AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = DummyGC Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Sat Mar 18 19:14:28 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.memory import gctransform +from pypy.rpython.memory import gctransform, support from pypy.objspace.flow.model import c_last_exception, Variable from pypy.rpython.memory.gctransform import var_needsgc, var_ispyobj from pypy.translator.translator import TranslationContext, graphof @@ -620,6 +620,7 @@ # tests for FrameworkGCTransformer def test_framework_simple(): + support.AddressLinkedList.unused_chunks = support.FreeList(support.CHUNK_SIZE + 2) # 'leaks' but well def g(x): return x + 1 class A(object): Modified: pypy/dist/pypy/rpython/memory/test/test_support.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_support.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_support.py Sat Mar 18 19:14:28 2006 @@ -1,5 +1,5 @@ from pypy.rpython.objectmodel import free_non_gc_object -from pypy.rpython.memory.support import AddressLinkedList +from pypy.rpython.memory.support import AddressLinkedList, FreeList, CHUNK_SIZE from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL from pypy.rpython.memory.test.test_llinterpsim import interpret @@ -11,11 +11,11 @@ ll.append(addr + 1) ll.append(addr + 2) a = ll.pop() - assert a == addr + assert a - addr == 2 a = ll.pop() assert a - addr == 1 a = ll.pop() - assert a - addr == 2 + assert a == addr assert ll.pop() == NULL assert ll.pop() == NULL ll.append(addr) @@ -28,6 +28,25 @@ ll.free() free_non_gc_object(ll) raw_free(addr) + + def test_big_access(self): + addr = raw_malloc(1) + ll = AddressLinkedList() + for i in range(1000): + print i + ll.append(addr + i) + for i in range(1000)[::-1]: + a = ll.pop() + assert a - addr == i + for i in range(1000): + print i + ll.append(addr + i) + for i in range(1000)[::-1]: + a = ll.pop() + assert a - addr == i + ll.free() + free_non_gc_object(ll) + raw_free(addr) def test_linked_list_annotate(): def f(): @@ -37,14 +56,24 @@ ll.append(addr + 1) ll.append(addr + 2) a = ll.pop() - res = a == addr + res = (a - addr == 2) a = ll.pop() res = res and (a - addr == 1) a = ll.pop() - res = res and (a - addr == 2) + res = res and a == addr res = res and (ll.pop() == NULL) res = res and (ll.pop() == NULL) ll.append(addr) + for i in range(100): + ll.append(addr + i) + for i in range(99, -1, -1): + a = ll.pop() + res = res and (a - addr == i) + for i in range(100): + ll.append(addr + i) + for i in range(99, -1, -1): + a = ll.pop() + res = res and (a - addr == i) ll.free() free_non_gc_object(ll) ll = AddressLinkedList() @@ -59,5 +88,8 @@ ## res = a.build_types(f, []) ## a.translator.specialize() ## a.translator.view() + assert f() + # grumpf: make sure that we don't get a polluted class attribute + AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) res = interpret(f, []) assert res From cfbolz at codespeak.net Sat Mar 18 21:46:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 18 Mar 2006 21:46:00 +0100 (CET) Subject: [pypy-svn] r24540 - pypy/dist/pypy/doc/weekly Message-ID: <20060318204600.314D1100B7@code0.codespeak.net> Author: cfbolz Date: Sat Mar 18 21:45:53 2006 New Revision: 24540 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: it got better already :-) Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Sat Mar 18 21:45:53 2006 @@ -49,7 +49,7 @@ This week Michael with the help of Carl, Samuele and Armin managed for the first time to compile the pypy interpreter together with our own garbage collector written in Python. Performance is not that great as -yet, about 100 times slower than CPython or about 16 times slower than +yet, about 40 times slower than CPython or about 7 times slower than with the Boehm collector. Given that we haven't tuned our garbage collector for performance at all, this isn't too bad. From cfbolz at codespeak.net Sat Mar 18 21:59:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 18 Mar 2006 21:59:44 +0100 (CET) Subject: [pypy-svn] r24541 - pypy/dist/pypy/rpython/memory Message-ID: <20060318205944.B3E79100B7@code0.codespeak.net> Author: cfbolz Date: Sat Mar 18 21:59:43 2006 New Revision: 24541 Modified: pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/rpython/memory/gctransform.py Log: try to read as much info out of the tables at runtime as possible Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Sat Mar 18 21:59:43 2006 @@ -109,6 +109,8 @@ class MarkSweepGC(GCBase): _alloc_flavor_ = "raw" + + _size_gc_header = gc_header_two_ints def __init__(self, start_heap_size=4096, get_roots=None): self.bytes_malloced = 0 @@ -124,17 +126,35 @@ self.collect() size = self.fixed_size(typeid) if self.is_varsize(typeid): - try: - varsize = rarithmetic.ovfcheck(length * self.varsize_item_sizes(typeid)) - except OverflowError: - raise MemoryError - size += varsize - size_gc_header = self.size_gc_header() + itemsize = self.varsize_item_sizes(typeid) + offset_to_length = self.varsize_offset_to_length(typeid) + return self.malloc_varsize(typeid, length, size, itemsize, offset_to_length) + return self.malloc_fixedsize(typeid, size) + + def malloc_fixedsize(self, typeid, size): + if self.bytes_malloced > self.heap_size: + self.collect() + size_gc_header = MarkSweepGC._size_gc_header result = raw_malloc(size + size_gc_header) -## print "mallocing %s, size %s at %s" % (typeid, size, result) - if self.is_varsize(typeid): - (result + self.varsize_offset_to_length(typeid)).signed[0] = length - self.init_gc_object(result, typeid) + result.signed[0] = 0 + result.signed[1] = typeid + self.malloced_objects.append(result) + self.bytes_malloced += size + size_gc_header + return result + size_gc_header + + def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length): + if self.bytes_malloced > self.heap_size: + self.collect() + try: + varsize = rarithmetic.ovfcheck(length * itemsize) + except OverflowError: + raise MemoryError + size += varsize + size_gc_header = MarkSweepGC._size_gc_header + result = raw_malloc(size + size_gc_header) + (result + offset_to_length + size_gc_header).signed[0] = length + result.signed[0] = 0 + result.signed[1] = typeid self.malloced_objects.append(result) self.bytes_malloced += size + size_gc_header return result + size_gc_header @@ -151,7 +171,7 @@ break # roots is a list of addresses to addresses: objects.append(curr.address[0]) - gc_info = curr.address[0] - self.size_gc_header() + gc_info = curr.address[0] - MarkSweepGC._size_gc_header # constants roots are not malloced and thus don't have their mark # bit reset gc_info.signed[0] = 0 @@ -161,7 +181,7 @@ ## print "object: ", curr if curr == NULL: break - gc_info = curr - self.size_gc_header() + gc_info = curr - MarkSweepGC._size_gc_header if gc_info.signed[0] == 1: continue typeid = gc_info.signed[1] @@ -198,14 +218,14 @@ typeid = curr.signed[1] size = self.fixed_size(typeid) if self.is_varsize(typeid): - length = (curr + self.size_gc_header() + self.varsize_offset_to_length(typeid)).signed[0] + length = (curr + MarkSweepGC._size_gc_header + self.varsize_offset_to_length(typeid)).signed[0] size += length * self.varsize_item_sizes(typeid) if curr.signed[0] == 1: curr.signed[0] = 0 newmo.append(curr) - curr_heap_size += size + self.size_gc_header() + curr_heap_size += size + MarkSweepGC._size_gc_header else: - freed_size += size + self.size_gc_header() + freed_size += size + MarkSweepGC._size_gc_header raw_free(curr) ## print "free %s bytes. the heap is %s bytes." % (freed_size, curr_heap_size) free_non_gc_object(self.malloced_objects) @@ -214,7 +234,7 @@ self.heap_size = curr_heap_size def size_gc_header(self, typeid=0): - return gc_header_two_ints + return MarkSweepGC._size_gc_header def init_gc_object(self, addr, typeid): addr.signed[0] = 0 Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 18 21:59:43 2006 @@ -834,20 +834,24 @@ classdef = bk.getuniqueclassdef(GCData.GCClass) s_gcdata = annmodel.SomeInstance(classdef) - malloc_graph = annhelper.getgraph(GCData.GCClass.malloc.im_func, - [s_gcdata, - annmodel.SomeInteger(nonneg=True), - annmodel.SomeInteger(nonneg=True)], - annmodel.SomeAddress()) + malloc_fixedsize_graph = annhelper.getgraph( + GCData.GCClass.malloc_fixedsize.im_func, + [s_gcdata, annmodel.SomeInteger(nonneg=True), + annmodel.SomeInteger(nonneg=True)], annmodel.SomeAddress()) + malloc_varsize_graph = annhelper.getgraph( + GCData.GCClass.malloc_varsize.im_func, + [s_gcdata] + [annmodel.SomeInteger(nonneg=True) for i in range(5)], + annmodel.SomeAddress()) annhelper.finish() # at this point, annotate all mix-level helpers self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph, attach_empty_cleanup=True) self.push_root_ptr = self.graph2funcptr(push_root_graph) self.graphs_to_inline[push_root_graph] = True - self.pop_root_ptr = self.graph2funcptr(pop_root_graph) + self.pop_root_ptr = self.graph2funcptr(pop_root_graph) self.graphs_to_inline[pop_root_graph] = True - self.malloc_ptr = self.graph2funcptr(malloc_graph, True) - self.graphs_to_inline[malloc_graph] = True + self.malloc_fixedsize_ptr = self.graph2funcptr(malloc_fixedsize_graph, True) + self.malloc_varsize_ptr = self.graph2funcptr(malloc_varsize_graph, True) + self.graphs_to_inline[malloc_fixedsize_graph] = True def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True @@ -990,10 +994,8 @@ v = varoftype(llmemory.Address) c_type_id = rmodel.inputconst(lltype.Signed, type_id) - if len(op.args) == 1: - v_length = rmodel.inputconst(lltype.Signed, 0) - else: - v_length = op.args[1] + info = self.type_info_list[type_id] + c_size = rmodel.inputconst(lltype.Signed, info["fixedsize"]) # surely there's a better way of doing this? s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(self.gcdata) @@ -1005,9 +1007,16 @@ "getfield", [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc", lltype.Void)], varoftype(r_gc.lowleveltype)) - newop = SpaceOperation("direct_call", - [self.malloc_ptr, newop0.result, c_type_id, v_length], - v) + if len(op.args) == 1: + args = [self.malloc_fixedsize_ptr, newop0.result, c_type_id, + c_size] + else: + v_length = op.args[1] + c_ofstolength = rmodel.inputconst(lltype.Signed, info['ofstolength']) + c_varitemsize = rmodel.inputconst(lltype.Signed, info['varitemsize']) + args = [self.malloc_varsize_ptr, newop0.result, c_type_id, + v_length, c_size, c_varitemsize, c_ofstolength] + newop = SpaceOperation("direct_call", args, v) ops, finally_ops = self.protect_roots(newop, livevars) ops.insert(0, newop0) ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result)) From cfbolz at codespeak.net Sat Mar 18 23:20:11 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 18 Mar 2006 23:20:11 +0100 (CET) Subject: [pypy-svn] r24542 - in pypy/dist/pypy: rpython/memory translator/c/test Message-ID: <20060318222011.6E8B5100B8@code0.codespeak.net> Author: cfbolz Date: Sat Mar 18 23:20:09 2006 New Revision: 24542 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/test/test_newgc.py Log: handle arrays of Voids correctly in the gc Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 18 23:20:09 2006 @@ -900,6 +900,9 @@ offsets = offsets_to_gc_pointers(ARRAY.OF) info["varofstoptrs"] = self.offsets2table(offsets) info["varitemsize"] = llmemory.sizeof(ARRAY.OF) + else: + info["varofstoptrs"] = self.offsets2table(()) + info["varitemsize"] = 0 return type_id def consider_constant(self, TYPE, value): Modified: pypy/dist/pypy/translator/c/test/test_newgc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_newgc.py (original) +++ pypy/dist/pypy/translator/c/test/test_newgc.py Sat Mar 18 23:20:09 2006 @@ -301,3 +301,15 @@ return len(a) + a[0] fn = self.getcompiled(f) py.test.raises(MemoryError, fn) + + def test_framework_array_of_void(self): + def f(): + a = [None] * 43 + b = [] + for i in range(1000000): + a.append(None) + b.append(len(a)) + return b[-1] + fn = self.getcompiled(f) + res = fn() + assert res == 43 + 1000000 From cfbolz at codespeak.net Sat Mar 18 23:36:40 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 18 Mar 2006 23:36:40 +0100 (CET) Subject: [pypy-svn] r24543 - pypy/dist/pypy/rpython/memory Message-ID: <20060318223640.EEC44100B8@code0.codespeak.net> Author: cfbolz Date: Sat Mar 18 23:36:38 2006 New Revision: 24543 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: if possible use non-conservative liveness analysis: if the block contains no non-gc ptrs that are not typeptrs (which are immortal anyway) we can stop considering a variable to be live when it is no longer used in the rest of the block. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 18 23:36:38 2006 @@ -105,7 +105,7 @@ has_exception_handler = block.exitswitch == c_last_exception for i, origop in enumerate(block.operations): num_ops_after_exc_raising = 0 - res = self.replacement_operations(origop, livevars) + res = self.replacement_operations(origop, livevars, block) try: ops, cleanup_before_exception = res except ValueError: @@ -189,10 +189,10 @@ if newops: block.operations = newops - def replacement_operations(self, op, livevars): + def replacement_operations(self, op, livevars, block): m = getattr(self, 'replace_' + op.opname, None) if m: - return m(op, livevars) + return m(op, livevars, block) else: return [op], [] @@ -225,12 +225,12 @@ result = varoftype(lltype.Void) return [SpaceOperation("gc_pop_alive_pyobj", [var], result)] - def replace_gc_protect(self, op, livevars): + def replace_gc_protect(self, op, livevars, block): """ protect this object from gc (make it immortal). the specific gctransformer needs to overwrite this""" raise NotImplementedError("gc_protect does not make sense for this gc") - def replace_gc_unprotect(self, op, livevars): + def replace_gc_unprotect(self, op, livevars, block): """ get this object back into gc control. the specific gctransformer needs to overwrite this""" raise NotImplementedError("gc_protect does not make sense for this gc") @@ -377,19 +377,19 @@ varoftype(lltype.Void), cleanup=None)) return result - def replace_gc_protect(self, op, livevars): + def replace_gc_protect(self, op, livevars, block): """ protect this object from gc (make it immortal) """ newops = self.push_alive(op.args[0]) newops[-1].result = op.result return newops, [] - def replace_gc_unprotect(self, op, livevars): + def replace_gc_unprotect(self, op, livevars, block): """ get this object back into gc control """ newops = self.pop_alive(op.args[0]) newops[-1].result = op.result return newops, [] - def replace_setfield(self, op, livevars): + def replace_setfield(self, op, livevars, block): if not var_needsgc(op.args[2]): return [op], [] oldval = varoftype(op.args[2].concretetype) @@ -400,7 +400,7 @@ result.append(op) return result, self.pop_alive(oldval) - def replace_setarrayitem(self, op, livevars): + def replace_setarrayitem(self, op, livevars, block): if not var_needsgc(op.args[2]): return [op], [] oldval = varoftype(op.args[2].concretetype) @@ -599,11 +599,11 @@ def pop_alive_nopyobj(self, var): return [] - def replace_gc_protect(self, op, livevars): + def replace_gc_protect(self, op, livevars, block): """ for boehm it is enough to do nothing""" return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] - def replace_gc_unprotect(self, op, livevars): + def replace_gc_unprotect(self, op, livevars, block): """ for boehm it is enough to do nothing""" return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] @@ -696,6 +696,19 @@ for a in gc_pointers_inside(v.items[i], adr + llmemory.itemoffsetof(t, i)): yield a +def needs_conservative_livevar_calculation(block): + from pypy.rpython.lltypesystem import rclass + vars = block.getvariables() + for var in vars: + TYPE = getattr(var, "concretetype", lltype.Ptr(lltype.PyObject)) + if isinstance(TYPE, lltype.Ptr) and not var_needsgc(var): + try: + lltype.castable(TYPE, rclass.CLASSTYPE) + except lltype.InvalidCast: + return True + else: + return False + class FrameworkGCTransformer(BoehmGCTransformer): def __init__(self, translator): @@ -980,8 +993,25 @@ newgcdependencies.append(ll_static_roots_inside) return newgcdependencies - def protect_roots(self, op, livevars): + def protect_roots(self, op, livevars, block, index=-1): livevars = [var for var in livevars if not var_ispyobj(var)] + if not needs_conservative_livevar_calculation(block): + print "found non-conservative block" + if index == -1: + index = block.operations.index(op) # XXX hum + needed = {} + for other_op in block.operations[index:]: + for arg in other_op.args: + needed[arg] = True + needed[other_op.result] = True + for exit in block.exits: + for arg in exit.args: + needed[arg] = True + newlivevars = [] + for var in livevars: + if var in needed: + newlivevars.append(var) + livevars = newlivevars newops = list(self.push_roots(livevars)) newops.append(op) return newops, tuple(self.pop_roots(livevars)) @@ -989,7 +1019,7 @@ replace_direct_call = protect_roots replace_indirect_call = protect_roots - def replace_malloc(self, op, livevars): + def replace_malloc(self, op, livevars, block): TYPE = op.args[0].value PTRTYPE = op.result.concretetype assert PTRTYPE.TO == TYPE @@ -1020,7 +1050,8 @@ args = [self.malloc_varsize_ptr, newop0.result, c_type_id, v_length, c_size, c_varitemsize, c_ofstolength] newop = SpaceOperation("direct_call", args, v) - ops, finally_ops = self.protect_roots(newop, livevars) + ops, finally_ops = self.protect_roots(newop, livevars, block, + block.operations.index(op)) ops.insert(0, newop0) ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result)) return ops, finally_ops, 1 From cfbolz at codespeak.net Sun Mar 19 00:00:39 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Mar 2006 00:00:39 +0100 (CET) Subject: [pypy-svn] r24544 - pypy/dist/pypy/rpython/memory Message-ID: <20060318230039.8F09B100B9@code0.codespeak.net> Author: cfbolz Date: Sun Mar 19 00:00:37 2006 New Revision: 24544 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: don't set the type_info_list to None, even after the call to finish Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sun Mar 19 00:00:37 2006 @@ -943,15 +943,15 @@ return cachedarray def finish(self): + finished = self.finished newgcdependencies = super(FrameworkGCTransformer, self).finish() - if self.type_info_list is not None: + if not finished: table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE, len(self.type_info_list), immortal=True) for tableentry, newcontent in zip(table, self.type_info_list): for key, value in newcontent.items(): setattr(tableentry, key, value) - self.type_info_list = None self.offsettable_cache = None # replace the type_info_table pointer in gcdata -- at this point, From pedronis at codespeak.net Sun Mar 19 00:04:34 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 19 Mar 2006 00:04:34 +0100 (CET) Subject: [pypy-svn] r24545 - pypy/dist/pypy/translator/c/src Message-ID: <20060318230434.78B70100B8@code0.codespeak.net> Author: pedronis Date: Sun Mar 19 00:04:29 2006 New Revision: 24545 Added: pypy/dist/pypy/translator/c/src/obmalloc.c - copied unchanged from r24542, vendor/cpython/Python-r242/dist/src/Objects/obmalloc.c Modified: pypy/dist/pypy/translator/c/src/standalone.h Log: obmalloc.c from Python 2.4.2 (from vendor) use it when translating standalone Modified: pypy/dist/pypy/translator/c/src/standalone.h ============================================================================== --- pypy/dist/pypy/translator/c/src/standalone.h (original) +++ pypy/dist/pypy/translator/c/src/standalone.h Sun Mar 19 00:04:29 2006 @@ -4,5 +4,9 @@ #include #include -#define PyObject_Malloc malloc -#define PyObject_Free free +#ifndef PYPY_NOT_MAIN_FILE +#ifndef WITH_PYMALLOC +#define WITH_PYMALLOC +#endif +#include "obmalloc.c" +#endif From cfbolz at codespeak.net Sun Mar 19 01:02:25 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Mar 2006 01:02:25 +0100 (CET) Subject: [pypy-svn] r24546 - pypy/dist/pypy/rpython/memory Message-ID: <20060319000225.91A91100B7@code0.codespeak.net> Author: cfbolz Date: Sun Mar 19 01:02:22 2006 New Revision: 24546 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: print in the opposite case Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sun Mar 19 01:02:22 2006 @@ -996,7 +996,6 @@ def protect_roots(self, op, livevars, block, index=-1): livevars = [var for var in livevars if not var_ispyobj(var)] if not needs_conservative_livevar_calculation(block): - print "found non-conservative block" if index == -1: index = block.operations.index(op) # XXX hum needed = {} @@ -1012,6 +1011,8 @@ if var in needed: newlivevars.append(var) livevars = newlivevars + else: + print "block which needs conservative livevar calculation found" newops = list(self.push_roots(livevars)) newops.append(op) return newops, tuple(self.pop_roots(livevars)) From cfbolz at codespeak.net Sun Mar 19 01:04:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Mar 2006 01:04:30 +0100 (CET) Subject: [pypy-svn] r24547 - pypy/dist/pypy/rpython/memory Message-ID: <20060319000430.B67F0100B7@code0.codespeak.net> Author: cfbolz Date: Sun Mar 19 01:04:29 2006 New Revision: 24547 Modified: pypy/dist/pypy/rpython/memory/support.py Log: use a bigger chunk size Modified: pypy/dist/pypy/rpython/memory/support.py ============================================================================== --- pypy/dist/pypy/rpython/memory/support.py (original) +++ pypy/dist/pypy/rpython/memory/support.py Sun Mar 19 01:04:29 2006 @@ -5,7 +5,7 @@ INT_SIZE = sizeof(lltype.Signed) -CHUNK_SIZE = 30 +CHUNK_SIZE = 1022 class FreeList(object): _alloc_flavor_ = "raw" From pedronis at codespeak.net Sun Mar 19 21:26:49 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 19 Mar 2006 21:26:49 +0100 (CET) Subject: [pypy-svn] r24557 - pypy/dist/pypy/translator/goal Message-ID: <20060319202649.64D94100AD@code0.codespeak.net> Author: pedronis Date: Sun Mar 19 21:26:47 2006 New Revision: 24557 Added: pypy/dist/pypy/translator/goal/gcbench.py pypy/dist/pypy/translator/goal/targetgcbench.py Modified: pypy/dist/pypy/translator/goal/buildcache2.py Log: add some kind of gc benchmark (ported from Java) Modified: pypy/dist/pypy/translator/goal/buildcache2.py ============================================================================== --- pypy/dist/pypy/translator/goal/buildcache2.py (original) +++ pypy/dist/pypy/translator/goal/buildcache2.py Sun Mar 19 21:26:47 2006 @@ -18,8 +18,8 @@ def getmodule(name): return space.getitem(w_modules, space.wrap(name)) - getmodule('parser').getdict() - print "*parser*" + getmodule('math').getdict() + print "*math*" for typedef in interptypes: w_typ = space.gettypeobject(typedef) Added: pypy/dist/pypy/translator/goal/gcbench.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/goal/gcbench.py Sun Mar 19 21:26:47 2006 @@ -0,0 +1,144 @@ +# Ported from a Java benchmark whose history is : +# This is adapted from a benchmark written by John Ellis and Pete Kovac +# of Post Communications. +# It was modified by Hans Boehm of Silicon Graphics. +# +# This is no substitute for real applications. No actual application +# is likely to behave in exactly this way. However, this benchmark was +# designed to be more representative of real applications than other +# Java GC benchmarks of which we are aware. +# It attempts to model those properties of allocation requests that +# are important to current GC techniques. +# It is designed to be used either to obtain a single overall performance +# number, or to give a more detailed estimate of how collector +# performance varies with object lifetimes. It prints the time +# required to allocate and collect balanced binary trees of various +# sizes. Smaller trees result in shorter object lifetimes. Each cycle +# allocates roughly the same amount of memory. +# Two data structures are kept around during the entire process, so +# that the measured performance is representative of applications +# that maintain some live in-memory data. One of these is a tree +# containing many pointers. The other is a large array containing +# double precision floating point numbers. Both should be of comparable +# size. +# +# The results are only really meaningful together with a specification +# of how much memory was used. It is possible to trade memory for +# better time performance. This benchmark should be run in a 32 MB +# heap, though we don't currently know how to enforce that uniformly. +# +# Unlike the original Ellis and Kovac benchmark, we do not attempt +# measure pause times. This facility should eventually be added back +# in. There are several reasons for omitting it for now. The original +# implementation depended on assumptions about the thread scheduler +# that don't hold uniformly. The results really measure both the +# scheduler and GC. Pause time measurements tend to not fit well with +# current benchmark suites. As far as we know, none of the current +# commercial Java implementations seriously attempt to minimize GC pause +# times. +# +# Known deficiencies: +# - No way to check on memory use +# - No cyclic data structures +# - No attempt to measure variation with object size +# - Results are sensitive to locking cost, but we dont +# check for proper locking +import os, time + +def println(s): + os.write(1, s+"\n") + +class Node(object): + + def __init__(self, l=None, r=None): + self.left = l + self.right = r + +kStretchTreeDepth = 18 # about 16Mb (for Java) +kLongLivedTreeDepth = 16 # about 4Mb (for Java) +kArraySize = 500000 # about 4Mb +kMinTreeDepth = 4 +kMaxTreeDepth = 16 + +def tree_size(i): + "Nodes used by a tree of a given size" + return (1 << (i + 1)) - 1 + +def num_iters(i): + "Number of iterations to use for a given tree depth" + return 2 * tree_size(kStretchTreeDepth) / tree_size(i); + +def populate(depth, node): + "Build tree top down, assigning to older objects." + if depth <= 0: + return + else: + depth -= 1 + node.left = Node() + node.right = Node() + populate(depth, node.left) + populate(depth, node.right) + +def make_tree(depth): + "Build tree bottom-up" + if depth <= 0: + return Node() + else: + return Node(make_tree(depth-1), make_tree(depth-1)) + +def print_diagnostics(): + "ought to print free/total memory" + pass + +def time_construction(depth): + niters = num_iters(depth) + println("Creating %d trees of depth %d" % (niters, depth)) + t_start = time.time() + for i in range(niters): + temp_tree = Node() + populate(depth, temp_tree) + temp_tree = None + t_finish = time.time() + println("\tTop down constrution took %f ms" % ((t_finish-t_start)*1000.)) + t_start = time.time() + for i in range(niters): + temp_tree = make_tree(depth) + temp_tree = None + t_finish = time.time() + println("\tBottom up constrution took %f ms" % ((t_finish-t_start)*1000.)) + +def main(): + println("Garbage Collector Test") + println(" Stretching memory with a binary tree of depth %d" % kStretchTreeDepth) + print_diagnostics() + t_start = time.time() + temp_tree = make_tree(kStretchTreeDepth) + temp_tree = None + + # Create a long lived object + println(" Creating a long-lived binary tree of depth %d" % kLongLivedTreeDepth) + long_lived_tree = Node() + populate(kLongLivedTreeDepth, long_lived_tree) + + # Create long-lived array, filling half of it + println(" Creating a long-lived array of %d doubles" % kArraySize) + array = [0.0] * kArraySize + i = 1 + while i < kArraySize/2: + array[i] = 1.0/i + i += 1 + print_diagnostics() + + for d in range(kMinTreeDepth, kMaxTreeDepth+1, 2): + time_construction(d) + + if long_lived_tree is None or array[1000] != 1.0/1000: + println("Failed") + + t_finish = time.time() + print_diagnostics() + println("Completed in %f ms." % ((t_finish-t_start)*1000.)) + + +if __name__ == '__main__': + main() Added: pypy/dist/pypy/translator/goal/targetgcbench.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/goal/targetgcbench.py Sun Mar 19 21:26:47 2006 @@ -0,0 +1,20 @@ +import os, sys +from pypy.translator.goal import gcbench + +def entry_point(argv): + gcbench.main() + return 0 + +# _____ Define and setup target ___ + +def target(*args): + return entry_point, None + +""" +Why is this a stand-alone target? + +The above target specifies None as the argument types list. +This is a case treated specially in the driver.py . If the list +of input types is empty, it is meant to be a list of strings, +actually implementing argv of the executable. +""" From cfbolz at codespeak.net Sun Mar 19 22:54:39 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Mar 2006 22:54:39 +0100 (CET) Subject: [pypy-svn] r24559 - in pypy/dist/pypy: rpython/memory translator/c Message-ID: <20060319215439.47B01100AD@code0.codespeak.net> Author: cfbolz Date: Sun Mar 19 22:54:38 2006 New Revision: 24559 Modified: pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/translator/c/gc.py Log: reduce the size of the gc header for mark and sweep by one word Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Sun Mar 19 22:54:38 2006 @@ -23,6 +23,9 @@ gc_header_two_ints = GCHeaderOffset( lltype.Struct("header", ("a", lltype.Signed), ("b", lltype.Signed))) +gc_header_one_int = GCHeaderOffset( + lltype.Struct("header", ("a", lltype.Signed))) + class GCError(Exception): pass @@ -110,7 +113,7 @@ class MarkSweepGC(GCBase): _alloc_flavor_ = "raw" - _size_gc_header = gc_header_two_ints + _size_gc_header = gc_header_one_int def __init__(self, start_heap_size=4096, get_roots=None): self.bytes_malloced = 0 @@ -136,8 +139,7 @@ self.collect() size_gc_header = MarkSweepGC._size_gc_header result = raw_malloc(size + size_gc_header) - result.signed[0] = 0 - result.signed[1] = typeid + result.signed[0] = typeid << 1 self.malloced_objects.append(result) self.bytes_malloced += size + size_gc_header return result + size_gc_header @@ -153,8 +155,7 @@ size_gc_header = MarkSweepGC._size_gc_header result = raw_malloc(size + size_gc_header) (result + offset_to_length + size_gc_header).signed[0] = length - result.signed[0] = 0 - result.signed[1] = typeid + result.signed[0] = typeid << 1 self.malloced_objects.append(result) self.bytes_malloced += size + size_gc_header return result + size_gc_header @@ -174,7 +175,7 @@ gc_info = curr.address[0] - MarkSweepGC._size_gc_header # constants roots are not malloced and thus don't have their mark # bit reset - gc_info.signed[0] = 0 + gc_info.signed[0] = gc_info.signed[0] & (~1) free_non_gc_object(roots) while 1: #mark curr = objects.pop() @@ -182,9 +183,9 @@ if curr == NULL: break gc_info = curr - MarkSweepGC._size_gc_header - if gc_info.signed[0] == 1: + if gc_info.signed[0] & 1: continue - typeid = gc_info.signed[1] + typeid = gc_info.signed[0] >> 1 offsets = self.offsets_to_gc_pointers(typeid) i = 0 while i < len(offsets): @@ -206,7 +207,7 @@ objects.append((item + offsets[j]).address[0]) j += 1 i += 1 - gc_info.signed[0] = 1 + gc_info.signed[0] = gc_info.signed[0] | 1 free_non_gc_object(objects) newmo = AddressLinkedList() curr_heap_size = 0 @@ -215,13 +216,13 @@ curr = self.malloced_objects.pop() if curr == NULL: break - typeid = curr.signed[1] + typeid = curr.signed[0] >> 1 size = self.fixed_size(typeid) if self.is_varsize(typeid): length = (curr + MarkSweepGC._size_gc_header + self.varsize_offset_to_length(typeid)).signed[0] size += length * self.varsize_item_sizes(typeid) - if curr.signed[0] == 1: - curr.signed[0] = 0 + if curr.signed[0] & 1: + curr.signed[0] = curr.signed[0] & (~1) newmo.append(curr) curr_heap_size += size + MarkSweepGC._size_gc_header else: @@ -237,8 +238,7 @@ return MarkSweepGC._size_gc_header def init_gc_object(self, addr, typeid): - addr.signed[0] = 0 - addr.signed[1] = typeid + addr.signed[0] = typeid << 1 init_gc_object_immortal = init_gc_object class SemiSpaceGC(GCBase): Modified: pypy/dist/pypy/translator/c/gc.py ============================================================================== --- pypy/dist/pypy/translator/c/gc.py (original) +++ pypy/dist/pypy/translator/c/gc.py Sun Mar 19 22:54:38 2006 @@ -288,14 +288,15 @@ return '%s = %s; /* for moving GCs */' % (args[1], args[0]) def common_gcheader_definition(self, defnode): - return [('flags', lltype.Signed), ('typeid', lltype.Signed)] + # XXX assumes mark and sweep + return [('typeid', lltype.Signed)] def common_gcheader_initdata(self, defnode): - # this more or less assumes mark-and-sweep gc + # XXX this more or less assumes mark-and-sweep gc o = defnode.obj while True: n = o._parentstructure() if n is None: break o = n - return [0, defnode.db.gctransformer.id_of_type[typeOf(o)]] + return [defnode.db.gctransformer.id_of_type[typeOf(o)] << 1] From cfbolz at codespeak.net Mon Mar 20 00:09:32 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 00:09:32 +0100 (CET) Subject: [pypy-svn] r24560 - pypy/dist/pypy/rpython/memory/test Message-ID: <20060319230932.9CDC8100AD@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 00:09:30 2006 New Revision: 24560 Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py Log: use small chunk sizes for the tests Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gc.py Mon Mar 20 00:09:30 2006 @@ -7,6 +7,7 @@ from pypy.rpython.memory.gc import GCError, MarkSweepGC, SemiSpaceGC from pypy.rpython.memory.gc import DeferredRefcountingGC, DummyGC from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE, CHUNK_SIZE, FreeList +from pypy.rpython.memory import support from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL from pypy.rpython.memory.simulator import MemorySimulatorError from pypy.rpython.memory import gclltype @@ -28,9 +29,11 @@ py.log.setconsumer("llinterp frame", stdout_ignore_ll_functions) py.log.setconsumer("llinterp operation", None) gclltype.prepare_graphs_and_create_gc = gclltype.create_gc + support.CHUNK_SIZE = 1 def teardown_module(mod): gclltype.prepare_graphs_and_create_gc = gclltype.create_no_gc + support.CHUNK_SIZE = CHUNK_SIZE class TestMarkSweepGC(object): def setup_class(cls): @@ -97,7 +100,7 @@ class TestMarkSweepGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): - AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well + AddressLinkedList.unused_chunks = FreeList(3) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp def teardown_class(cls): @@ -112,7 +115,7 @@ class TestSemiSpaceGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): - AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well + AddressLinkedList.unused_chunks = FreeList(3) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = SemiSpaceGC @@ -132,7 +135,7 @@ class TestDeferredRefcountingGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): - AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well + AddressLinkedList.unused_chunks = FreeList(3) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = DeferredRefcountingGC @@ -151,7 +154,7 @@ class TestDummyGCRunningOnLLinterp(TestMarkSweepGC): def setup_class(cls): - AddressLinkedList.unused_chunks = FreeList(CHUNK_SIZE + 2) # 'leaks' but well + AddressLinkedList.unused_chunks = FreeList(3) # 'leaks' but well cls.prep_old = gclltype.prepare_graphs_and_create_gc gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp gclltype.use_gc = DummyGC From cfbolz at codespeak.net Mon Mar 20 01:12:50 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 01:12:50 +0100 (CET) Subject: [pypy-svn] r24561 - pypy/dist/pypy/rpython/memory/test Message-ID: <20060320001250.AD1B8100AD@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 01:12:48 2006 New Revision: 24561 Modified: pypy/dist/pypy/rpython/memory/test/test_support.py Log: make the test to something useful at the expense of making it take longer :-( Modified: pypy/dist/pypy/rpython/memory/test/test_support.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_support.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_support.py Mon Mar 20 01:12:48 2006 @@ -1,8 +1,10 @@ from pypy.rpython.objectmodel import free_non_gc_object from pypy.rpython.memory.support import AddressLinkedList, FreeList, CHUNK_SIZE +from pypy.rpython.memory import support from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL from pypy.rpython.memory.test.test_llinterpsim import interpret + class TestAddressLinkedList(object): def test_simple_access(self): addr = raw_malloc(100) @@ -32,16 +34,16 @@ def test_big_access(self): addr = raw_malloc(1) ll = AddressLinkedList() - for i in range(1000): + for i in range(3000): print i ll.append(addr + i) - for i in range(1000)[::-1]: + for i in range(3000)[::-1]: a = ll.pop() assert a - addr == i - for i in range(1000): + for i in range(3000): print i ll.append(addr + i) - for i in range(1000)[::-1]: + for i in range(3000)[::-1]: a = ll.pop() assert a - addr == i ll.free() @@ -64,14 +66,14 @@ res = res and (ll.pop() == NULL) res = res and (ll.pop() == NULL) ll.append(addr) - for i in range(100): + for i in range(3000): ll.append(addr + i) - for i in range(99, -1, -1): + for i in range(2999, -1, -1): a = ll.pop() res = res and (a - addr == i) - for i in range(100): + for i in range(3000): ll.append(addr + i) - for i in range(99, -1, -1): + for i in range(2999, -1, -1): a = ll.pop() res = res and (a - addr == i) ll.free() From nik at codespeak.net Mon Mar 20 10:48:19 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 20 Mar 2006 10:48:19 +0100 (CET) Subject: [pypy-svn] r24575 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060320094819.15955100CA@code0.codespeak.net> Author: nik Date: Mon Mar 20 10:48:17 2006 New Revision: 24575 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: make casts from/to uint more correct. Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Mon Mar 20 10:48:17 2006 @@ -159,9 +159,25 @@ op_cast_char_to_int = noop op_cast_unichar_to_int = noop + # NB: behaviour for casts to chars is undefined for too wide ints op_cast_int_to_char = noop op_cast_int_to_unichar = noop - op_cast_int_to_uint = noop op_cast_int_to_longlong = noop # XXX to_float missing + def masking_cast(self, op, mask): + from pypy.translator.squeak.node import HelperNode + mask_name, mask_code = self.int_masks[mask] + helper = HelperNode(self.gen, Message(mask_name), mask_code) + cast = helper.apply([op.args[0]]) + self.gen.schedule_node(helper) + return Assignment(op.result, cast) + + def op_cast_int_to_uint(self, op): + return self.masking_cast(op, "uint") + + def op_cast_uint_to_int(self, op): + return self.masking_cast(op, "int") + + op_truncate_longlong_to_int = noop + Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 20 10:48:17 2006 @@ -181,3 +181,13 @@ res = chr(res) assert expected_res == res +def test_cast_int_to_uint(): + def lloptest(i): + return llop.cast_int_to_uint(Unsigned, i) + llfunctest(lloptest, (-1,)) + +def test_cast_uint_to_int(): + def lloptest(i): + return llop.cast_uint_to_int(Signed, i) + llfunctest(lloptest, (r_uint(sys.maxint + 1),)) + From ericvrp at codespeak.net Mon Mar 20 12:31:07 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Mon, 20 Mar 2006 12:31:07 +0100 (CET) Subject: [pypy-svn] r24578 - pypy/dist/pypy/translator/tool Message-ID: <20060320113107.A11E3100D8@code0.codespeak.net> Author: ericvrp Date: Mon Mar 20 12:31:01 2006 New Revision: 24578 Modified: pypy/dist/pypy/translator/tool/cbuild.py Log: Support Darwinports on Darwin Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Mon Mar 20 12:31:01 2006 @@ -63,6 +63,16 @@ if include_dirs is None: include_dirs = [] + library_dirs = [] + if sys.platform == 'darwin': # support Fink & Darwinports + for s in ('/sw/', '/opt/local/'): + if s + 'include' not in include_dirs and \ + os.path.exists(s + 'include'): + include_dirs.append(s + 'include') + if s + 'lib' not in library_dirs and \ + os.path.exists(s + 'lib'): + library_dirs.append(s + 'lib') + dirpath = cfiles[0].dirpath() lastdir = dirpath.chdir() ensure_correct_math() @@ -113,6 +123,7 @@ 'ext_modules': [ Extension(modname, [str(cfile) for cfile in cfiles], include_dirs=include_dirs, + library_dirs=library_dirs, extra_compile_args=extra_compile_args, libraries=libraries,) ], @@ -276,10 +287,14 @@ if sys.platform == 'win32': self.link_extra += ['/DEBUG'] # generate .pdb file if sys.platform == 'darwin': - if '/sw/include' not in self.include_dirs: - self.include_dirs.append('/sw/include') - if '/sw/lib' not in self.library_dirs: - self.library_dirs.append('/sw/lib') + # support Fink & Darwinports + for s in ('/sw/', '/opt/local/'): + if s + 'include' not in self.include_dirs and \ + os.path.exists(s + 'include'): + self.include_dirs.append(s + 'include') + if s + 'lib' not in self.library_dirs and \ + os.path.exists(s + 'lib'): + self.library_dirs.append(s + 'lib') self.compile_extra += ['-O2'] if outputfilename is None: From ericvrp at codespeak.net Mon Mar 20 12:50:35 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Mon, 20 Mar 2006 12:50:35 +0100 (CET) Subject: [pypy-svn] r24579 - pypy/dist/pypy/rpython/l3interp/test Message-ID: <20060320115035.AC0AE100D8@code0.codespeak.net> Author: ericvrp Date: Mon Mar 20 12:50:34 2006 New Revision: 24579 Modified: pypy/dist/pypy/rpython/l3interp/test/test_convert.py pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py Log: Add py.test --view support to l3interp Modified: pypy/dist/pypy/rpython/l3interp/test/test_convert.py ============================================================================== --- pypy/dist/pypy/rpython/l3interp/test/test_convert.py (original) +++ pypy/dist/pypy/rpython/l3interp/test/test_convert.py Mon Mar 20 12:50:34 2006 @@ -1,11 +1,14 @@ import py from pypy.rpython.l3interp import convertgraph, l3interp from pypy.translator.translator import TranslationContext +from pypy import conftest def l3ify(f, inputargs): t = TranslationContext() t.buildannotator().build_types(f, inputargs) t.buildrtyper().specialize() + if conftest.option.view: + t.view() conv = convertgraph.LL2L3Converter() g = conv.convert_graph(t.graphs[0]) # XXX this vile, vile hack prevents the TranslationContext from Modified: pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py ============================================================================== --- pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py (original) +++ pypy/dist/pypy/rpython/l3interp/test/test_l3interp.py Mon Mar 20 12:50:34 2006 @@ -5,6 +5,7 @@ from pypy.translator.translator import TranslationContext from pypy.annotation import policy from pypy.rpython.lltypesystem import lltype +from pypy import conftest def setup_module(mod): mod._cleanups = [] @@ -20,6 +21,8 @@ pol.allow_someobjects = False t.buildannotator(policy=pol).build_types(func, inputargs) t.buildrtyper().specialize() + if conftest.option.view: + t.view() from pypy.translator.tool.cbuild import skip_missing_compiler from pypy.translator.c import genc From arigo at codespeak.net Mon Mar 20 13:57:34 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Mar 2006 13:57:34 +0100 (CET) Subject: [pypy-svn] r24582 - pypy/dist/pypy/doc Message-ID: <20060320125734.672A0100E1@code0.codespeak.net> Author: arigo Date: Mon Mar 20 13:57:20 2006 New Revision: 24582 Modified: pypy/dist/pypy/doc/jit.txt Log: JIT Doc: some notes about the merging/bookkeeping done by the compilers produced by the hint-rtyper. Wrote down a possible approach, to be reviewed :-) Modified: pypy/dist/pypy/doc/jit.txt ============================================================================== --- pypy/dist/pypy/doc/jit.txt (original) +++ pypy/dist/pypy/doc/jit.txt Mon Mar 20 13:57:20 2006 @@ -106,4 +106,132 @@ helpers; when the graph of the now-compiler is running, these helpers will produce new ``int_add`` and ``int_sub`` operations. -(Extra merging/bookkeeping blocks are actually inserted; XXX explain...) +Merging and bookkeeping +----------------------- + +XXX the following is not the way it works currently, but rather a +proposal for how it might work -- although it's all open to changes. It +is a mix of how Psyco and the Flow Object Space work. + +Unlike ll_plus_minus() above, any realistic interpreter needs to handle +two complications: + +1. Jumping or looping opcodes. When looping back to a previous bytecode + position, the now-compiler must not continue to compile again and again; + it must generate a loop in the residual graph as well, and stop + compiling. + +2. Conditional branches. Unless the condition is known at compile time, + the compiler must generate a branch in the residual graph and compile + both paths. + +Keep in mind that this is all about how the interpreter is transformed +to become a compiler. Unless explicitly specified, I don't speak about +the interpreted user program here. + +As a reminder, this is handled in the Flow Space as follows: + +1. When a residual operation is about to be generated, we check if the + bytecode position closed back to an already-seen position. To do so, + for each bytecode position we save a "state". The state remembers + the bytecode interpreter's frame state, as a pattern of Variables and + Constants; in addition, the state points to the residual block that + corresponded to that position. + +2. A branch forces the current block to fork in two "EggBlocks". This + makes a tree with a "SpamBlock" at the root and two EggBlock children, + which themselves might again have two EggBlock children, and so on. + The Flow Space resumes its analysis from the start of the root + SpamBlock and explores each branch of this tree in turn. Unexplored + branches are remembered for later. + +In Psyco: + +1. A state is saved at the beginning of each bytecode, as in the Flow + Space. (There are actually memory-saving tricks to avoid saving a + state for each and every bytecode.) We close a loop in the residual + graph as soon as we reach an already-seen bytecode position, but + only if the states are "compatible enough". Indeed, as in the PyPy + JIT, Psyco states store more than just Variable/Constant: they store + "blue" containers detailing individual field's content. Blue + containers of too-different shapes are not "compatible enough". In + addition, some Constants can be marked as "fixed" to prevent them + from being merged with different Constants and becoming Variables. + +2. Branching in Psyco work as in the Flow Space, with the exception that + each condition has got a "likely" and a "less likely" outcome. The + compilation follows the "likely" path only. The "unlikely" paths + are only explored if at run-time the execution actually reaches them. + (When it does, the same trick as in the Flow Space is used: + compilation restarts from the root SpamBlock and follows the complete + branch of the EggBlock tree.) + +3. A different kind of branching that doesn't occur in the Flow Space: + promoting a value from Variable to Constant. This is used e.g. when + an indirect function call is about to be performed. A typical + example is to call a PyTypeObject's slot based on the type of a + PyObject instance. In this case, Psyco considers the PyObject's + ob_type field as a Variable, which it turns into a Constant. + Conceptually, the current residual block is ended with a "switch" + and every time a different run-time value reaches this point, a new + case is compiled and added to the switch. (As in 2., the compilation + is restarted from the root SpamBlock until it reaches that point + again.) + +The "tree of EggBlocks" approach doesn't work too well in general. For +example, it unrolls loops infinitely if they are not loops in the +bytecode but loops in the implementation of a single opcode (we had this +problem working on the annotator in Vilnius). + +The current preliminary work on the hint-rtyper turns the interpreter +into a compiler that saves its state all the time everywhere. This +makes sure that loops are not unexpectedly unrolled, and that the code +that follows an if/else is not duplicated (as it would be in the +tree-of-EggBlocks approach). It is also extremely inefficient and +perfect to explode the memory usage. + +I think we could try to target the following model -- which also has the +advantage that simple calls in the interpreter are still simple calls in +the compiler, as in Psyco: + +1. We only save the state at one point. We probably need a hint to + specify where this point is -- at the beginning of the bytecode + interpreter loop. It is easy to know in advance which information + needs to be stored in each state: the tuple of green variables is used + as a key in a global dict; the content of the red variables is stored + as a state under this key. Several states can be stored under the same + key if they are not "compatible enough". + +2. Branching: a possible approach would be to try to have the compiler + produce a residual graph that has the same shape as the original + graph in the interpreter, at least as far as the conditions are + unknown at compile-time. (This would remove the branches whose + conditions are known at compile time, and unroll all-green loops + like the bytecode interpreter loop itself.) + +3. Promoting a Variable to a Constant, or, in colored terms, a red + variable to a green one (using a hint which we have not implemented + so far): this is the case where we have no choice but suspend the + compilation, and wait for execution to provide real values. We will + implement this case later, but I mention it now because it seems that + there are solutions compatible with this model, including Psyco's + (see 3. above). + +The motivation to do point 2. differently than in Psyco is that it is +both more powerful (no extra unrolling/duplication of code) and closer +to what we have already now: the bookkeeping code inserted by the +hint-rtyper in the compiler's graphs. In Psyco it would have been a +mess to write that bookkeeping code everywhere by hand, not to mention +changing it to experiment with other ideas. + +Random notes +----------------- + +An idea to consider: red variables in the compiler could come with +a concrete value attached too, which represents a real execution-time +value. The compiler would perform concrete operations on it in addition +to generating residual operations. In other words, the compiler would +also perform directly some interpretation as it goes along. In this +way, we can avoid some of the recompilation by using this attached value +e.g. as the first switch case in the red-to-green promotions, or as a +hint about which outcome of a run-time condition is more likely. From nik at codespeak.net Mon Mar 20 14:10:46 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 20 Mar 2006 14:10:46 +0100 (CET) Subject: [pypy-svn] r24584 - in pypy/dist/pypy/rpython: . test Message-ID: <20060320131046.6C94C100DB@code0.codespeak.net> Author: nik Date: Mon Mar 20 14:10:45 2006 New Revision: 24584 Modified: pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/test/test_llinterp.py Log: fix a bug with int_truediv in the llinterpreter. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Mon Mar 20 14:10:45 2006 @@ -115,6 +115,8 @@ 'lt': True, 'le': True, 'eq': True, 'ne': True, 'is_true': True} +ops_returning_a_float = {'truediv': True} + def checkptr(ptr): return isinstance(lltype.typeOf(ptr), lltype.Ptr) @@ -692,7 +694,8 @@ optup += 'and_', 'or_', 'lshift', 'rshift', 'xor' for opname in optup: assert opname in opimpls - if typ is int and opname not in ops_returning_a_bool: + if typ is int and opname not in ops_returning_a_bool \ + and opname not in ops_returning_a_float: adjust_result = 'intmask' else: adjust_result = '' Modified: pypy/dist/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_llinterp.py (original) +++ pypy/dist/pypy/rpython/test/test_llinterp.py Mon Mar 20 14:10:45 2006 @@ -1,6 +1,7 @@ import py from pypy.rpython.lltypesystem.lltype import typeOf, pyobjectptr, Ptr, PyObject, Void +from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.llinterp import LLInterpreter, LLException, log from pypy.rpython.rmodel import inputconst from pypy.translator.translator import TranslationContext @@ -355,6 +356,15 @@ assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 0 +def test_int_truediv(): + from pypy.rpython.lltypesystem.lltype import Float + def f(i, j): + return llop.int_truediv(Float, i, j) + for args in (4, 2), (3, 4): + res = interpret(f, list(args)) + assert isinstance(res, float) + assert res == float(args[0]) / args[1] + #__________________________________________________________________ # # Test objects and instances From bea at codespeak.net Mon Mar 20 14:29:59 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Mon, 20 Mar 2006 14:29:59 +0100 (CET) Subject: [pypy-svn] r24588 - pypy/extradoc/pypy.org Message-ID: <20060320132959.9AFAB100A5@code0.codespeak.net> Author: bea Date: Mon Mar 20 14:29:58 2006 New Revision: 24588 Added: pypy/extradoc/pypy.org/revision_march2006.txt Log: notes regarding pypy-org Added: pypy/extradoc/pypy.org/revision_march2006.txt ============================================================================== --- (empty file) +++ pypy/extradoc/pypy.org/revision_march2006.txt Mon Mar 20 14:29:58 2006 @@ -0,0 +1,53 @@ +pypy.org;revision March 2006 +-------------------------------- + +In order to have an external website servicing information in connection +to pressreleases and more external newsletter the pypy org page needs updating. + +The following changes/adds needs to be done: + +- change eu logo to IST logo (done) +- change navigation to links about: + Home, News, Consortium, Links, Documentation, Community/Coding + - Links being a page with links to sisterprojects, to commission pages etc + - Documentation being a page to access published reports, pressreleases, talks, papers, + diagrams, tutorials, pictures, film? + +- info regarding industrial impact (why PyPy, gains? what will it provide, which industries/languages + do we target - who will have use of PyPy???? This info could be on the main page (HOME) + + +---------------------------------------------------------------------------------------------------------- + +Here are the urls for the Link page: + +Related EU projects and url:s: +6th Framework Programme +http://fp6.cordis.lu/index.cfm?fuseaction=UserSite.FP6HomePage +Calibre: +http://www.calibre.ie +Edos: +http://www.pps.jussieu.fr/~dicosmo/EDOS/index.html +Amigo: +http://www.hitech-projects.com/euprojects/amigo/ +tOSSad +http://www.tossad.org/ +Cospa +http://www.cospa-project.org/ +Floss +http://www.infonomics.nl/FLOSS/ + +Related Python F/OSS projects: +Cpython? +Ironpython? +Jython? +Twisted? +Plone? + +Related F/OSS projects: +Oz? +..? +..? +--------------------------- +Do we want to have a link to universities, conferences and companies we are in touch with/cooperating with? +Such as UIB, UCD, Iona, x, y, z... \ No newline at end of file From pedronis at codespeak.net Mon Mar 20 14:42:42 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 14:42:42 +0100 (CET) Subject: [pypy-svn] r24590 - pypy/dist/pypy/doc Message-ID: <20060320134242.BA18B100CB@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 14:42:41 2006 New Revision: 24590 Modified: pypy/dist/pypy/doc/jit.txt Log: clarification of the current state of things. Modified: pypy/dist/pypy/doc/jit.txt ============================================================================== --- pypy/dist/pypy/doc/jit.txt (original) +++ pypy/dist/pypy/doc/jit.txt Mon Mar 20 14:42:41 2006 @@ -184,10 +184,10 @@ problem working on the annotator in Vilnius). The current preliminary work on the hint-rtyper turns the interpreter -into a compiler that saves its state all the time everywhere. This +into a compiler that saves its state at _all_ join-points permanently. This makes sure that loops are not unexpectedly unrolled, and that the code that follows an if/else is not duplicated (as it would be in the -tree-of-EggBlocks approach). It is also extremely inefficient and +tree-of-EggBlocks approach). It is also inefficient and perfect to explode the memory usage. I think we could try to target the following model -- which also has the From nik at codespeak.net Mon Mar 20 14:43:33 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 20 Mar 2006 14:43:33 +0100 (CET) Subject: [pypy-svn] r24591 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060320134333.2690B100DC@code0.codespeak.net> Author: nik Date: Mon Mar 20 14:43:26 2006 New Revision: 24591 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: full support for floats in gensqueak. Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Mon Mar 20 14:43:26 2006 @@ -100,7 +100,7 @@ return self.format_Instance(value) elif value is None: return "nil" - elif isinstance(value, int): + elif isinstance(value, (int, float)): return str(value) elif isinstance(value, ootype._class): return self.format_Instance(value._INSTANCE) Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Mon Mar 20 14:43:26 2006 @@ -31,6 +31,13 @@ 'classof': 'class', 'same_as': 'yourself', 'bool_not': 'not', + + 'cast_int_to_float': 'asFloat', + 'float_div': '/', # overrides the div definition in number_ops + 'float_fmod': r'\\', # we can't really distinguish mod and fmod + 'float_floor': 'floor', + # XXX this potentially incorrect (may return LargeIntegers) + 'cast_float_to_int': 'truncated', } number_ops = { @@ -45,7 +52,7 @@ 'mul': '*', 'div': '//', 'floordiv': '//', - #'truediv': '/', # XXX fix this when we have float support + 'truediv': '/ asFloat', 'mod': r'\\', 'eq': '=', 'ne': '~=', @@ -74,6 +81,10 @@ self.codef = CodeFormatter(gen) def format(self, op): + if self.ops.has_key(op.opname): + name = self.ops[op.opname] + sent = Message(name).send_to(op.args[0], op.args[1:]) + return self.codef.format(sent.assign_to(op.result)) opname_parts = op.opname.split("_") if opname_parts[0] in self.number_opprefixes: return self.format_number_op( @@ -82,26 +93,29 @@ if op_method is not None: return self.codef.format(op_method(op)) else: - if not self.ops.has_key(op.opname): - raise NotImplementedError( + raise NotImplementedError( "operation not supported: %s" % op.opname) - name = self.ops[op.opname] - sent = Message(name).send_to(op.args[0], op.args[1:]) - return self.codef.format(sent.assign_to(op.result)) def format_number_op(self, op, ptype, opname): - message = Message(self.number_ops[opname]) - sent_message = message.send_to(op.args[0], op.args[1:]) + messages = self.number_ops[opname].split() + msg = Message(messages[0]) + sent_message = msg.send_to(op.args[0], op.args[1:]) + for add_message in messages[1:]: + sent_message = Message(add_message).send_to(sent_message, []) if opname in self.wrapping_ops \ and self.int_masks.has_key(ptype): - # XXX how do i get rid of this import? - from pypy.translator.squeak.node import HelperNode - mask_name, mask_code = self.int_masks[ptype] - helper = HelperNode(self.gen, Message(mask_name), mask_code) - sent_message = helper.apply([sent_message]) - self.gen.schedule_node(helper) + sent_message = self.apply_mask_helper(sent_message, ptype) return self.codef.format(sent_message.assign_to(op.result)) + def apply_mask_helper(self, receiver, mask_type_name): + # XXX how do i get rid of this import? + from pypy.translator.squeak.node import HelperNode + mask_name, mask_code = self.int_masks[mask_type_name] + helper = HelperNode(self.gen, Message(mask_name), mask_code) + result = helper.apply([receiver]) + self.gen.schedule_node(helper) + return result + def op_oosend(self, op): message_name = op.args[0].value message_name = self.gen.unique_method_name( @@ -150,10 +164,16 @@ msg = Message(function_name).send_to(FunctionNode.FUNCTIONS, op.args[1:]) return msg.assign_to(op.result) - def op_cast_bool_to_int(self, op): - msg = Message("ifTrue: [1] ifFalse: [0]") + def cast_bool(self, op, true_repr, false_repr): + msg = Message("ifTrue: [%s] ifFalse: [%s]" % (true_repr, false_repr)) return msg.send_to(op.args[0], []).assign_to(op.result) + def op_cast_bool_to_int(self, op): + return self.cast_bool(op, "1", "0") + + def op_cast_bool_to_float(self, op): + return self.cast_bool(op, "1.0", "0.0") + op_cast_bool_to_uint = op_cast_bool_to_int op_cast_char_to_int = noop @@ -163,14 +183,9 @@ op_cast_int_to_char = noop op_cast_int_to_unichar = noop op_cast_int_to_longlong = noop - # XXX to_float missing def masking_cast(self, op, mask): - from pypy.translator.squeak.node import HelperNode - mask_name, mask_code = self.int_masks[mask] - helper = HelperNode(self.gen, Message(mask_name), mask_code) - cast = helper.apply([op.args[0]]) - self.gen.schedule_node(helper) + cast = self.apply_mask_helper(op.args[0], mask) return Assignment(op.result, cast) def op_cast_int_to_uint(self, op): @@ -181,3 +196,7 @@ op_truncate_longlong_to_int = noop + def op_cast_float_to_uint(self, op): + truncated = Message("truncated").send_to(op.args[0], []) + return Assignment(op.result, self.apply_mask_helper(truncated, "uint")) + Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Mon Mar 20 14:43:26 2006 @@ -4,7 +4,7 @@ from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Bool, Char, UniChar -from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong +from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong, Float from pypy.rpython.test.test_llinterp import interpret def optest(testcase): @@ -61,6 +61,7 @@ ("div", Signed, 7, 3), ("floordiv", Signed, 7, 3), # XXX what about division by zero? ("floordiv", Signed, -7, 3), + ("truediv", Float, 7, 4), ("mod", Signed, 9, 4), ("mod", Signed, 9, -4), ("eq", Bool, 1, 1), @@ -120,6 +121,36 @@ for t in tests: yield optest, t +def test_floatoperations_unary(): + for llopname in "abs", "neg", "floor": + exec """def lloptest(): + return llop.float_%s(Float, -1.5)""" % llopname + expected_res = llinterpret(lloptest, ()) + res = sqinterpret(lloptest, ()) + assert expected_res == float(res) # because floor might return a squeak int + +def test_floatoperations_is_true(): + def istrue(): + return llop.float_is_true(Bool, 0.0) + llfunctest(istrue, ()) + +def test_floatoperations_binary(): + for llopname in "add", "sub", "mul", "div", "mod", "fmod", \ + "floordiv", "truediv": + exec """def lloptest(i): + f = llop.cast_int_to_float(Float, i) + return llop.float_%s(Float, f, 1.25)""" % llopname + expected_res = llinterpret(lloptest, (3,)) + res = sqinterpret(lloptest, (3,)) + assert expected_res == float(res) # because of floordiv + +def test_floatoperations_binary_bool(): + for llopname in "eq", "ne", "gt", "lt", "ge", "le": + exec """def lloptest(i): + f = llop.cast_int_to_float(Float, i) + return llop.float_%s(Bool, f, 1.25)""" % llopname + yield llfunctest, lloptest, (3,) + def test_booloperations(): def bool_not(i): if i == 1: @@ -146,7 +177,7 @@ yield llfunctest, lloptest, (1, 2) def test_cast_bool(): - tests = ("int", Signed), ("uint", Unsigned) # XXX missing float + tests = ("int", Signed), ("uint", Unsigned), ("float", Float) for target_name, target_type in tests: exec """def lloptest(i): b = llop.int_is_true(Bool, i) @@ -168,7 +199,7 @@ yield llfunctest, lloptest, (1,) def test_cast_int(): - tests = [("char", Char), ("unichar", UniChar), + tests = [("char", Char), ("unichar", UniChar), ("float", Float), ("longlong", SignedLongLong), ("uint", Unsigned)] for target_name, target_type in tests: exec """def lloptest(i): @@ -176,9 +207,11 @@ % (target_name, target_type._name) args = (2,) expected_res = llinterpret(lloptest, args) - res = int(sqinterpret(lloptest, args)) + res = sqinterpret(lloptest, args) if isinstance(expected_res, (str, unicode)): - res = chr(res) + res = chr(int(res)) + else: + expected_res = str(expected_res) assert expected_res == res def test_cast_int_to_uint(): @@ -191,3 +224,11 @@ return llop.cast_uint_to_int(Signed, i) llfunctest(lloptest, (r_uint(sys.maxint + 1),)) +def test_cast_float(): + tests = [("int", Signed), ("uint", Unsigned)] + for target_name, target_type in tests: + exec """def lloptest(): + return llop.cast_float_to_%s(%s, -1.5)""" \ + % (target_name, target_type._name) + yield llfunctest, lloptest, () + From mwh at codespeak.net Mon Mar 20 14:46:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 20 Mar 2006 14:46:15 +0100 (CET) Subject: [pypy-svn] r24593 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060320134615.CFF49100CB@code0.codespeak.net> Author: mwh Date: Mon Mar 20 14:46:14 2006 New Revision: 24593 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: a complete sprint report? Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Mon Mar 20 14:46:14 2006 @@ -1,38 +1,39 @@ Post-PyCon 2006 Sprint Report ============================= -After PyCon this year, we held four days of sprints, 27th Feb-2 March 2006. There were lots -of people new to PyPy and a couple of old friends we hadn't seen for a -while. - -Here are the list of people participating in the sprint: -( some for only for one day, others for the full sprint) - -Gene Oden -Bob Ippolito -Josh Gilbert -Geroge Paci -Pat Maupin -Martin Blais -Stuart Williams -Jiwon Seo -Michael Twomey -Anders Lehmann -Nik Haldimann -Samuele Pedronis -Armin Rigo -Michael Hudson -Wanja Saatkamp -Beatrice D?ring -Anders Chrigstrom -Richard Emslie -(Christian Tismer) -(Holger Krekel) +After PyCon this year, we held four days of sprints, from 27th of +February to the 2nd of March 2006. There were lots of people new to +PyPy and a couple of old friends we hadn't seen for a while. + +Here is the list of people participating in the sprint: + + * Gene Oden + * Bob Ippolito + * Josh Gilbert + * Geroge Paci + * Pat Maupin + * Martin Blais + * Stuart Williams + * Jiwon Seo + * Michael Twomey (Mick) + * Anders Lehmann (Anders) + * Nik Haldimann + * Samuele Pedronis + * Armin Rigo + * Michael Hudson (Michael) + * Wanja Saatkamp + * Beatrice D?ring + * Anders Chrigstrom (Arre) + * Richard Emslie + * (Christian Tismer -- worked mostly on stackless) + * (Holger Krekel -- was unfortunately ill for most of the sprint) +Not all people participated for the full sprint; attendance generally +tailed off over the course of the four days. -The announced goals for the sprint was: +The announced goals for the sprint were: -- Work on an 'rctypes' module aiming at letting us use a ctypes + - Work on an 'rctypes' module aiming at letting us use a ctypes implementation of an extension module from the compiled pypy-c. - Writing ctypes implementations of modules to be used by the above @@ -51,11 +52,9 @@ - Generally experiment with PyPy -- for example, play with transparent distribution of objects or coroutines and stackless features at application level. - - Day 1 -------- +----- Monday began with a 45 minute introduction/tutorial by Michael (which was videoed -- watch for it arriving on codespeak soon-ish) and then a @@ -99,13 +98,58 @@ The Tuesday began with a status meeting where we talked about what we'd acheived the day before and basically decided that most of us -would carry on with the same things (this proved to be a much more -accurate plan than the previous day's...). +would carry on with the same things. + +Armin, Mick and Gene, having broken all the rctypes tests the day +before, started to use the new 'extregistry' to get things to start +working again. + +Nik, Michael and Samuele continued to move rtyper tests from being +lltypesystem-only to running on both typesystems, and implementing the +support thus required in the ootypesystem. The hardest part off this +was supporting class attributes, as this is not something we assume +the to-be-targeted supports natively (this wasn't finished until +Wednesday). + +Arre, Stuart and Anders implemented more Python 2.5 features, in +particular those described by PEP 343. + +Bob and Richard played with the LLVM JIT. The hardest part of this +seemed to be working out which libraries to link against... + +Later in the day Moshe and Michael played around with the stackless +features, in particular coroutines, and in the end made their play +into a new test. Day 3 ----- -By Wednesday, the sprint was thinning out... +By Wednesday, the sprint was thinning out, but a fair amount of work +still got done. + +Samuele and Nik finished off and merged the short-lived ooclassattrs +branch, sorted out some exception issues and moved on to feared topic +of 'specialized methods' -- when one method in the input source +becomes more than one method in the backend's view. This didn't turn +out to be as bad as suspected, and by the end of the day the main the +ootypesystem lacked was an actual backend... + +Richard took Michael on a quick tour of LLVM and then they both worked +on adding support for the various offset types to LLVM, a prerequisite +for LLVM being able to use the framework GCs. + +Armin and Gene worked more on rctypes, using the work of the previous +two days to make it work again in a nicer and hopefully more +sustainable way than before. + +Anders, Stuart and Arre worked on more Python 2.5 PEPs, finishing the +343 work and generally tidying. + +In the afternoon, Michael compiled a fresh Python from SVN HEAD (many +many new features had been implemented by the Python code sprint in +the room next door) and attempted to run the PyPy test suite with it. +This uncovered a number of problems both in PyPy and in Python, some +of which were easier to fix than others. Day 4 ----- From cfbolz at codespeak.net Mon Mar 20 14:49:58 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 14:49:58 +0100 (CET) Subject: [pypy-svn] r24596 - pypy/dist/pypy/doc/weekly Message-ID: <20060320134958.A50AC100D3@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 14:49:57 2006 New Revision: 24596 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: just add a pointer to the demo file for the logic object space Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Mon Mar 20 14:49:57 2006 @@ -39,9 +39,11 @@ One of the more visible results of the sprint is the Logic Object Space, a very small (in terms of lines of code) object space that implements dataflow -variables similar to what Oz has in Python. XXX more +variables similar to what Oz has in Python. For examples on how it can be used, +see the files `uthread.py`_. .. _`logic sprint report`: http://codespeak.net/pypy/extradoc/sprintinfo/louvain-la-neuve-2006/report.html +.. _`uthread.py`: http://codespeak.net/svn/pypy/dist/demo/uthread.py Garbage Collection ================== From hpk at codespeak.net Mon Mar 20 15:07:45 2006 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 20 Mar 2006 15:07:45 +0100 (CET) Subject: [pypy-svn] r24599 - pypy/dist/pypy/doc Message-ID: <20060320140745.86FAE100EB@code0.codespeak.net> Author: hpk Date: Mon Mar 20 15:07:34 2006 New Revision: 24599 Modified: pypy/dist/pypy/doc/extradoc.txt Log: add a nice link (i found via google) to a slide-intro to CLR and IL (under the hood) to our extradocs section. Modified: pypy/dist/pypy/doc/extradoc.txt ============================================================================== --- pypy/dist/pypy/doc/extradoc.txt (original) +++ pypy/dist/pypy/doc/extradoc.txt Mon Mar 20 15:07:34 2006 @@ -46,6 +46,10 @@ distributed multi-user/multi-programmer virtual world. * `LLVM`_ the low level virtual machine project. + +* `CLR under the hood`_ (powerpoint, works with open office) gives + a good introduction to the underlying models of Microsoft's Common + Language Runtime, the Intermediate Language, JIT and GC issues. * spyweb_ translates Python programs to Scheme. @@ -56,6 +60,7 @@ * `GNU lightning`_ generates assembly language at runtime. +.. _`CLR under the hood`: http://download.microsoft.com/download/2/4/d/24dfac0e-fec7-4252-91b9-fb2310603f14/CLRUnderTheHood.BradA.ppt .. _Stackless: http://stackless.com .. _Psyco: http://psyco.sourceforge.net .. _Jython: http://www.jython.org From mwh at codespeak.net Mon Mar 20 15:08:45 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 20 Mar 2006 15:08:45 +0100 (CET) Subject: [pypy-svn] r24600 - in pypy/dist/pypy/translator/c: . test Message-ID: <20060320140845.92473100EB@code0.codespeak.net> Author: mwh Date: Mon Mar 20 15:08:44 2006 New Revision: 24600 Added: pypy/dist/pypy/translator/c/exceptiontransform.py (contents, props changed) pypy/dist/pypy/translator/c/test/test_exceptiontransform.py (contents, props changed) Log: a first cut of an exception transform. not useful yet, probably, but it's a start. copy/paste/hacked from pypy.translator.llvm.backendopt.exception. Added: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Mon Mar 20 15:08:44 2006 @@ -0,0 +1,55 @@ +from pypy.translator.unsimplify import split_block +from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ + c_last_exception, SpaceOperation +from pypy.rpython import rclass + + +n_calls = n_calls_patched = 0 + +def create_exception_handling(translator, graph): + """After an exception in a direct_call (or indirect_call), that is not caught + by an explicit + except statement, we need to reraise the exception. So after this + direct_call we need to test if an exception had occurred. If so, we return + from the current graph with an unused value (false/0/0.0/null). + Because of the added exitswitch we need an additional block. + """ + global n_calls, n_calls_patched + n_calls_patched_begin = n_calls_patched + e = translator.rtyper.getexceptiondata() + for block in graph.iterblocks(): + last_operation = len(block.operations)-1 + if block.exitswitch == c_last_exception: + last_operation -= 1 + for i in range(last_operation, -1, -1): + op = block.operations[i] + if op.opname not in ('direct_call', 'indirect_call'): + continue + n_calls += 1 + called_can_raise = True #XXX maybe we even want a list of possible exceptions + if not called_can_raise: + continue + n_calls_patched += 1 + + afterblock = split_block(translator, graph, block, i+1) + + block.exitswitch = c_last_exception + + #non-exception case + block.exits[0].exitcase = block.exits[0].llexitcase = None + + #exception occurred case + etype = Variable('extra_etype') + etype.concretetype = e.lltype_of_exception_type + evalue = Variable('extra_evalue') + evalue.concretetype = e.lltype_of_exception_value + + l = Link([etype, evalue], graph.exceptblock) + l.extravars(etype, evalue) + l.prevblock = block + l.exitcase = Exception + r_case = rclass.get_type_repr(translator.rtyper) + l.llexitcase = r_case.convert_const(l.exitcase) + + block.exits.append(l) + Added: pypy/dist/pypy/translator/c/test/test_exceptiontransform.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Mon Mar 20 15:08:44 2006 @@ -0,0 +1,37 @@ +from pypy.translator.translator import TranslationContext, graphof +from pypy.translator.c import exceptiontransform +from pypy.objspace.flow.model import c_last_exception + +from pypy import conftest + +def transform_func(fn, inputtypes): + t = TranslationContext() + t.buildannotator().build_types(fn, inputtypes) + t.buildrtyper().specialize() + if conftest.option.view: + t.view() + g = graphof(t, fn) + exceptiontransform.create_exception_handling(t, g) + if conftest.option.view: + t.view() + for b in g.iterblocks(): + l = len(b.operations) + for i in range(l): + op = b.operations[i] + if op.opname == 'direct_call': + assert i == l-1 + assert b.exitswitch is c_last_exception + return t, g + +def test_simple(): + def one(): + return 1 + + def foo(): + one() + one() + + t, g = transform_func(foo, []) + + + From cfbolz at codespeak.net Mon Mar 20 15:24:46 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 15:24:46 +0100 (CET) Subject: [pypy-svn] r24602 - in pypy/extradoc/talk: img pycon2006 Message-ID: <20060320142446.84040100DC@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 15:24:11 2006 New Revision: 24602 Added: pypy/extradoc/talk/img/ pypy/extradoc/talk/img/py-web.png - copied unchanged from r24575, pypy/extradoc/talk/22c3/py-web.png pypy/extradoc/talk/pycon2006/manmoon.png - copied unchanged from r24575, pypy/extradoc/talk/22c3/manmoon.png pypy/extradoc/talk/pycon2006/method_talk.pdf pypy/extradoc/talk/pycon2006/method_talk.rst2pdfconfig pypy/extradoc/talk/pycon2006/subscribers.png - copied unchanged from r24575, pypy/extradoc/talk/22c3/plots/subscribers.png Modified: pypy/extradoc/talk/pycon2006/method_talk.txt Log: add pdf version of method talk Added: pypy/extradoc/talk/pycon2006/method_talk.pdf ============================================================================== Files (empty file) and pypy/extradoc/talk/pycon2006/method_talk.pdf Mon Mar 20 15:24:11 2006 differ Added: pypy/extradoc/talk/pycon2006/method_talk.rst2pdfconfig ============================================================================== --- (empty file) +++ pypy/extradoc/talk/pycon2006/method_talk.rst2pdfconfig Mon Mar 20 15:24:11 2006 @@ -0,0 +1,14 @@ +rest_sources = [ + 'method_talk.txt', +] + +rest_options = ['--use-latex-footnotes', '--use-latex-toc'] +toc_depth = 2 + +logo = '../img/py-web.png' +heading = 'Agile Open-Source Methods, Businesses and EU-funding' +# pagebreak = True +# possible fonts: +# times, helvetica, new century schoolbock, avant garde, palatino + +font = 'avant garde' Modified: pypy/extradoc/talk/pycon2006/method_talk.txt ============================================================================== --- pypy/extradoc/talk/pycon2006/method_talk.txt (original) +++ pypy/extradoc/talk/pycon2006/method_talk.txt Mon Mar 20 15:24:11 2006 @@ -122,9 +122,8 @@ Sprints facilitate participation ============================================================ -.. image:: plots/subscribers.png - :width: 600 - :height: 450 +.. image:: subscribers.png + :scale: 60 .. From cfbolz at codespeak.net Mon Mar 20 16:08:47 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 16:08:47 +0100 (CET) Subject: [pypy-svn] r24608 - pypy/extradoc/sprintinfo/pycon06 Message-ID: <20060320150847.3D98E100F0@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 16:08:45 2006 New Revision: 24608 Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Log: some small glitches Modified: pypy/extradoc/sprintinfo/pycon06/sprint-report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon06/sprint-report.txt (original) +++ pypy/extradoc/sprintinfo/pycon06/sprint-report.txt Mon Mar 20 16:08:45 2006 @@ -128,10 +128,10 @@ still got done. Samuele and Nik finished off and merged the short-lived ooclassattrs -branch, sorted out some exception issues and moved on to feared topic +branch, sorted out some exception issues and moved on to the feared topic of 'specialized methods' -- when one method in the input source becomes more than one method in the backend's view. This didn't turn -out to be as bad as suspected, and by the end of the day the main the +out to be as bad as suspected, and by the end of the day the main thing the ootypesystem lacked was an actual backend... Richard took Michael on a quick tour of LLVM and then they both worked @@ -143,7 +143,7 @@ sustainable way than before. Anders, Stuart and Arre worked on more Python 2.5 PEPs, finishing the -343 work and generally tidying. +343 work and generally tidying some things up. In the afternoon, Michael compiled a fresh Python from SVN HEAD (many many new features had been implemented by the Python code sprint in From pedronis at codespeak.net Mon Mar 20 16:17:25 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 16:17:25 +0100 (CET) Subject: [pypy-svn] r24610 - pypy/dist/pypy/jit/test Message-ID: <20060320151725.5EE69100EF@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 16:17:19 2006 New Revision: 24610 Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: a passing test to clarify current llabstractinterp behavior. Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Mon Mar 20 16:17:19 2006 @@ -309,8 +309,34 @@ s = t.s return s.n graph2, insns = abstrinterp(ll_function, [0], []) - - + +def test_merge_different_sharing(): + S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + T = lltype.GcStruct('T', ('s1', lltype.Ptr(S)), ('s2', lltype.Ptr(S))) + def ll_function(flag, x,y): + if flag: + t = lltype.malloc(T) + s = lltype.malloc(S) + s.x = x + s.y = y + t.s1 = s + t.s2 = s + else: + t = lltype.malloc(T) + s1 = lltype.malloc(S) + s2 = lltype.malloc(S) + s1.x = x + s2.x = x + s1.y = y + s2.y = y + t.s1 = s1 + t.s2 = s2 + # the two t joining here are not mergeable + return (t.s1.x+t.s1.x)*(t.s2.y+t.s2.y) + graph2, insns = abstrinterp(ll_function, [0, 2, 3], []) + assert insns['int_add'] == 4 + assert insns['int_mul'] == 2 + def test_cast_pointer(): S = lltype.GcStruct('S', ('n1', lltype.Signed), ('n2', lltype.Signed)) PS = lltype.Ptr(S) From auc at codespeak.net Mon Mar 20 16:34:21 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 20 Mar 2006 16:34:21 +0100 (CET) Subject: [pypy-svn] r24613 - pypy/dist/demo Message-ID: <20060320153421.64A44100EF@code0.codespeak.net> Author: auc Date: Mon Mar 20 16:34:10 2006 New Revision: 24613 Modified: pypy/dist/demo/producerconsumer.py Log: move stuff to test file Modified: pypy/dist/demo/producerconsumer.py ============================================================================== --- pypy/dist/demo/producerconsumer.py (original) +++ pypy/dist/demo/producerconsumer.py Mon Mar 20 16:34:10 2006 @@ -31,33 +31,3 @@ print S - -def lgenerate(n, L): - """wait-needed version of generate""" - print "generator waits on L being needed" - wait_needed(L) - Tail = newvar() - L == (n, Tail) - print "generator bound L to", L - lgenerate(n+1, Tail) - -def lsum(L, a, limit): - """this version of sum controls the generator""" - print "sum", a - if limit > 0: - Head, Tail = newvar(), newvar() - print "sum waiting on L" - L == (Head, Tail) # or Head, Tail == L ? - return lsum(Tail, a+Head, limit-1) - else: - return a - -print "lazy producer consummer" -print "before" -Y = newvar() -T = newvar() -uthread(lgenerate, 0, Y) -T == uthread(lsum, Y, 0, 10) -print "after" - -print T From auc at codespeak.net Mon Mar 20 16:38:57 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 20 Mar 2006 16:38:57 +0100 (CET) Subject: [pypy-svn] r24614 - pypy/dist/pypy/objspace/test Message-ID: <20060320153857.B22B6100EC@code0.codespeak.net> Author: auc Date: Mon Mar 20 16:38:51 2006 New Revision: 24614 Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: is_unbound -> is_free Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Mon Mar 20 16:38:51 2006 @@ -7,11 +7,11 @@ def test_simple(self): X = newvar() - assert is_unbound(X) + assert is_free(X) bind(X, 1) assert type(X) == int - assert not is_unbound(X) - assert not is_unbound(1) + assert is_bound(X) + assert is_bound(1) raises(TypeError, bind, 1, 2) def test_setitem(self): @@ -22,10 +22,10 @@ d[7].append(x) y = d[5], d[6], d.values(), d.items() for x in [d[5], d[6], d[7][0]]: - assert is_unbound(d[5]) + assert is_free(d[5]) bind(x, 1) for x in [d[5], d[6], d[7][0]]: - assert not is_unbound(d[5]) + assert is_bound(d[5]) def test_unbound_unification_simple(self): X = newvar() @@ -60,7 +60,7 @@ Y = newvar() assert X == Y assert X == 1 - assert not is_unbound(Y) + assert is_bound(Y) assert Y == 1 def test_ne_of_unified_vars(self): @@ -73,10 +73,10 @@ X = newvar() Y = newvar() assert cmp(X, Y) == 0 - assert is_unbound(X) - assert is_unbound(Y) + assert is_free(X) + assert is_free(Y) assert X == 1 - assert not is_unbound(Y) + assert is_bound(Y) assert Y == 1 def test_is(self): From pedronis at codespeak.net Mon Mar 20 17:03:01 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 17:03:01 +0100 (CET) Subject: [pypy-svn] r24615 - pypy/dist/pypy/jit Message-ID: <20060320160301.19A80100ED@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 17:02:49 2006 New Revision: 24615 Modified: pypy/dist/pypy/jit/llabstractinterp.py Log: this was old broken code by some refactoring. Fix keepalive Modified: pypy/dist/pypy/jit/llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/llabstractinterp.py (original) +++ pypy/dist/pypy/jit/llabstractinterp.py Mon Mar 20 17:02:49 2006 @@ -862,7 +862,7 @@ memo = FlattenMemo() a_ptr.flatten(memo) for a in memo.result: - if (a.is_variable and + if (isinstance(a.runtimevar, AVariable) and not a.getconcretetype()._is_atomic()): self.genop('keepalive', [a.forcegenvarorconst()], lltype.Void) From pedronis at codespeak.net Mon Mar 20 17:08:25 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 17:08:25 +0100 (CET) Subject: [pypy-svn] r24616 - pypy/dist/pypy/jit/test Message-ID: <20060320160825.BC435100ED@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 17:08:13 2006 New Revision: 24616 Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: another test. here we don't merge again for subtle but correct structure sharing issues. Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Mon Mar 20 17:08:13 2006 @@ -7,6 +7,7 @@ from pypy.annotation import model as annmodel from pypy.jit.llabstractinterp import LLAbstractInterp, Policy from pypy.objspace.flow import model as flowmodel +from pypy.rpython import objectmodel def annotation(a, x): T = lltype.typeOf(x) @@ -307,8 +308,27 @@ s.n = 4 if flag: s = t.s - return s.n + return s.n+2 graph2, insns = abstrinterp(ll_function, [0], []) + assert insns['int_add'] == 2 # no merge + +def test_merge_cross_substructure(): + S = lltype.Struct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('s1', S), ('n', lltype.Float)) + + def ll_function(flag): + t = lltype.malloc(T) + t.s.n = 3 + t.s1.n = 3 + if flag: + s = t.s + else: + s = t.s1 + n = s.n + objectmodel.keepalive_until_here(t) + return n+2 + graph2, insns = abstrinterp(ll_function, [0], []) + assert insns['int_add'] == 2 # no merge def test_merge_different_sharing(): S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) @@ -334,6 +354,7 @@ # the two t joining here are not mergeable return (t.s1.x+t.s1.x)*(t.s2.y+t.s2.y) graph2, insns = abstrinterp(ll_function, [0, 2, 3], []) + # no merge assert insns['int_add'] == 4 assert insns['int_mul'] == 2 From cfbolz at codespeak.net Mon Mar 20 17:17:42 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 17:17:42 +0100 (CET) Subject: [pypy-svn] r24617 - in pypy/dist/pypy/translator/c: . test Message-ID: <20060320161742.9CBD9100EE@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 17:17:31 2006 New Revision: 24617 Modified: pypy/dist/pypy/translator/c/exceptiontransform.py pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Log: small refactoring to the exception transformation: use a class to prevent the growth of a Huge Function From Hell (tm) use the RaiseAnalyzer to find out which calls can raise at all Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Mon Mar 20 17:17:31 2006 @@ -1,55 +1,56 @@ from pypy.translator.unsimplify import split_block +from pypy.translator.backendopt import canraise from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ c_last_exception, SpaceOperation from pypy.rpython import rclass -n_calls = n_calls_patched = 0 +class ExceptionTransformer(object): + def __init__(self, translator): + self.translator = translator + self.raise_analyzer = canraise.RaiseAnalyzer(translator) + + def create_exception_handling(self, graph): + """After an exception in a direct_call (or indirect_call), that is not caught + by an explicit + except statement, we need to reraise the exception. So after this + direct_call we need to test if an exception had occurred. If so, we return + from the current graph with an unused value (false/0/0.0/null). + Because of the added exitswitch we need an additional block. + """ + exc_data = self.translator.rtyper.getexceptiondata() + for block in graph.iterblocks(): + last_operation = len(block.operations)-1 + if block.exitswitch == c_last_exception: + last_operation -= 1 + for i in range(last_operation, -1, -1): + op = block.operations[i] + print "considering op", op, i + if not self.raise_analyzer.can_raise(op): + continue + called_can_raise = True #XXX maybe we even want a list of possible exceptions + if not called_can_raise: + continue + + afterblock = split_block(self.translator, graph, block, i+1) + + block.exitswitch = c_last_exception + + #non-exception case + block.exits[0].exitcase = block.exits[0].llexitcase = None + + #exception occurred case + etype = Variable('extra_etype') + etype.concretetype = exc_data.lltype_of_exception_type + evalue = Variable('extra_evalue') + evalue.concretetype = exc_data.lltype_of_exception_value + + l = Link([etype, evalue], graph.exceptblock) + l.extravars(etype, evalue) + l.prevblock = block + l.exitcase = Exception + r_case = rclass.get_type_repr(self.translator.rtyper) + l.llexitcase = r_case.convert_const(l.exitcase) -def create_exception_handling(translator, graph): - """After an exception in a direct_call (or indirect_call), that is not caught - by an explicit - except statement, we need to reraise the exception. So after this - direct_call we need to test if an exception had occurred. If so, we return - from the current graph with an unused value (false/0/0.0/null). - Because of the added exitswitch we need an additional block. - """ - global n_calls, n_calls_patched - n_calls_patched_begin = n_calls_patched - e = translator.rtyper.getexceptiondata() - for block in graph.iterblocks(): - last_operation = len(block.operations)-1 - if block.exitswitch == c_last_exception: - last_operation -= 1 - for i in range(last_operation, -1, -1): - op = block.operations[i] - if op.opname not in ('direct_call', 'indirect_call'): - continue - n_calls += 1 - called_can_raise = True #XXX maybe we even want a list of possible exceptions - if not called_can_raise: - continue - n_calls_patched += 1 - - afterblock = split_block(translator, graph, block, i+1) - - block.exitswitch = c_last_exception - - #non-exception case - block.exits[0].exitcase = block.exits[0].llexitcase = None - - #exception occurred case - etype = Variable('extra_etype') - etype.concretetype = e.lltype_of_exception_type - evalue = Variable('extra_evalue') - evalue.concretetype = e.lltype_of_exception_value - - l = Link([etype, evalue], graph.exceptblock) - l.extravars(etype, evalue) - l.prevblock = block - l.exitcase = Exception - r_case = rclass.get_type_repr(translator.rtyper) - l.llexitcase = r_case.convert_const(l.exitcase) - - block.exits.append(l) + block.exits.append(l) Modified: pypy/dist/pypy/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Mon Mar 20 17:17:31 2006 @@ -11,16 +11,10 @@ if conftest.option.view: t.view() g = graphof(t, fn) - exceptiontransform.create_exception_handling(t, g) + etrafo = exceptiontransform.ExceptionTransformer(t) + etrafo.create_exception_handling(g) if conftest.option.view: t.view() - for b in g.iterblocks(): - l = len(b.operations) - for i in range(l): - op = b.operations[i] - if op.opname == 'direct_call': - assert i == l-1 - assert b.exitswitch is c_last_exception return t, g def test_simple(): @@ -32,6 +26,16 @@ one() t, g = transform_func(foo, []) + assert len(list(g.iterblocks())) == 2 # graph does not change - - +def test_raises(): + def one(x): + if x: + raise ValueError() + + def foo(): + one(0) + one(1) + t, g = transform_func(foo, []) + assert len(list(g.iterblocks())) == 5 + From cfbolz at codespeak.net Mon Mar 20 17:18:20 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 17:18:20 +0100 (CET) Subject: [pypy-svn] r24618 - pypy/dist/pypy/translator/c Message-ID: <20060320161820.1E486100F2@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 17:18:18 2006 New Revision: 24618 Modified: pypy/dist/pypy/translator/c/exceptiontransform.py Log: what is this used for? Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Mon Mar 20 17:18:18 2006 @@ -28,9 +28,6 @@ print "considering op", op, i if not self.raise_analyzer.can_raise(op): continue - called_can_raise = True #XXX maybe we even want a list of possible exceptions - if not called_can_raise: - continue afterblock = split_block(self.translator, graph, block, i+1) From cfbolz at codespeak.net Mon Mar 20 17:58:19 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 17:58:19 +0100 (CET) Subject: [pypy-svn] r24623 - in pypy/dist/pypy/translator/c: . test Message-ID: <20060320165819.DE278100ED@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 17:58:18 2006 New Revision: 24623 Modified: pypy/dist/pypy/translator/c/exceptiontransform.py pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Log: first step in removing exceptions completely: use RPyExceptionOccured to check whether an exception is active Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Mon Mar 20 17:58:18 2006 @@ -1,14 +1,35 @@ from pypy.translator.unsimplify import split_block from pypy.translator.backendopt import canraise from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ - c_last_exception, SpaceOperation + c_last_exception, SpaceOperation, checkgraph +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.memory.lladdress import NULL from pypy.rpython import rclass +from pypy.rpython.rarithmetic import r_uint +PrimitiveErrorValue = {lltype.Signed: -1, + lltype.Unsigned: r_uint(-1), + lltype.Float: -1.0, + lltype.Char: chr(255), + lltype.Bool: True, + llmemory.Address: NULL, + lltype.Void: None} + +def error_value(T): + if isinstance(T, lltype.Primitive): + return Constant(PrimitiveErrorValue[T], T) + elif isinstance(T, Ptr): + return Constant(None, T) + assert 0, "not implemented yet" class ExceptionTransformer(object): def __init__(self, translator): self.translator = translator self.raise_analyzer = canraise.RaiseAnalyzer(translator) + RPYEXC_OCCURED_TYPE = lltype.FuncType([], lltype.Bool) + self.rpyexc_occured_ptr = Constant(lltype.functionptr( + RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", external="C"), + lltype.Ptr(RPYEXC_OCCURED_TYPE)) def create_exception_handling(self, graph): """After an exception in a direct_call (or indirect_call), that is not caught @@ -19,35 +40,35 @@ Because of the added exitswitch we need an additional block. """ exc_data = self.translator.rtyper.getexceptiondata() - for block in graph.iterblocks(): - last_operation = len(block.operations)-1 - if block.exitswitch == c_last_exception: - last_operation -= 1 - for i in range(last_operation, -1, -1): - op = block.operations[i] - print "considering op", op, i - if not self.raise_analyzer.can_raise(op): - continue - - afterblock = split_block(self.translator, graph, block, i+1) - - block.exitswitch = c_last_exception - - #non-exception case - block.exits[0].exitcase = block.exits[0].llexitcase = None - - #exception occurred case - etype = Variable('extra_etype') - etype.concretetype = exc_data.lltype_of_exception_type - evalue = Variable('extra_evalue') - evalue.concretetype = exc_data.lltype_of_exception_value - - l = Link([etype, evalue], graph.exceptblock) - l.extravars(etype, evalue) - l.prevblock = block - l.exitcase = Exception - r_case = rclass.get_type_repr(self.translator.rtyper) - l.llexitcase = r_case.convert_const(l.exitcase) + for block in list(graph.iterblocks()): #collect the blocks before changing them + self.transform_block(graph, block) + checkgraph(graph) + + def transform_block(self, graph, block): + last_operation = len(block.operations)-1 + if block.exitswitch == c_last_exception: + last_operation -= 1 + for i in range(last_operation, -1, -1): + op = block.operations[i] + print "considering op", op, i + if not self.raise_analyzer.can_raise(op): + continue + + afterblock = split_block(self.translator, graph, block, i+1) + + var_exc_occured = Variable() + var_exc_occured.concretetype = lltype.Bool + + block.operations.append(SpaceOperation("direct_call", [self.rpyexc_occured_ptr], var_exc_occured)) + block.exitswitch = var_exc_occured + + #non-exception case + block.exits[0].exitcase = block.exits[0].llexitcase = False + + #exception occurred case + l = Link([error_value(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) + l.prevblock = block + l.exitcase = l.llexitcase = True - block.exits.append(l) + block.exits.append(l) Modified: pypy/dist/pypy/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Mon Mar 20 17:58:18 2006 @@ -37,5 +37,5 @@ one(0) one(1) t, g = transform_func(foo, []) - assert len(list(g.iterblocks())) == 5 + assert len(list(g.iterblocks())) == 4 From arigo at codespeak.net Mon Mar 20 18:10:03 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Mar 2006 18:10:03 +0100 (CET) Subject: [pypy-svn] r24624 - in pypy/dist/pypy/jit: . test Message-ID: <20060320171003.D9452100EF@code0.codespeak.net> Author: arigo Date: Mon Mar 20 18:09:56 2006 New Revision: 24624 Modified: pypy/dist/pypy/jit/hintannotator.py pypy/dist/pypy/jit/test/test_hint_annotation.py Log: 'keepalive' support in the hint-annotator. Modified: pypy/dist/pypy/jit/hintannotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator.py (original) +++ pypy/dist/pypy/jit/hintannotator.py Mon Mar 20 18:09:56 2006 @@ -28,5 +28,8 @@ vcontainerdef = self.bookkeeper.getvirtualcontainerdef(TYPE) return hintmodel.SomeLLAbstractContainer(vcontainerdef) + def consider_op_keepalive(self, hs_v): + pass + _registeroperations(HintAnnotator.__dict__, hintmodel) Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/dist/pypy/jit/test/test_hint_annotation.py Mon Mar 20 18:09:56 2006 @@ -7,18 +7,21 @@ from pypy.rpython.objectmodel import hint from pypy.annotation import model as annmodel from pypy.annotation.policy import AnnotatorPolicy +from pypy.translator.backendopt.inline import auto_inlining from pypy import conftest P_OOPSPEC = AnnotatorPolicy() P_OOPSPEC.oopspec = True -def hannotate(func, argtypes, policy=None, annotator=False): +def hannotate(func, argtypes, policy=None, annotator=False, inline=None): # build the normal ll graphs for ll_function t = TranslationContext() a = t.buildannotator() a.build_types(func, argtypes) rtyper = t.buildrtyper() rtyper.specialize() + if inline: + auto_inlining(t, inline) graph1 = graphof(t, func) # build hint annotator types hannotator = HintAnnotator(policy=policy) @@ -409,6 +412,7 @@ return acc assert ll_plus_minus("+-+", 0, 2) == 2 hannotate(ll_plus_minus, [str, int, int]) + hannotate(ll_plus_minus, [str, int, int], inline=999) def test_invalid_hint_1(): S = lltype.GcStruct('S', ('x', lltype.Signed)) From pedronis at codespeak.net Mon Mar 20 19:17:56 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 19:17:56 +0100 (CET) Subject: [pypy-svn] r24635 - in pypy/dist/pypy/lib/logic: . basic_store computation_space Message-ID: <20060320181756.263CE100EF@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 19:17:52 2006 New Revision: 24635 Added: pypy/dist/pypy/lib/logic/__init__.py (contents, props changed) pypy/dist/pypy/lib/logic/basic_store/__init__.py (contents, props changed) pypy/dist/pypy/lib/logic/computation_space/__init__.py (contents, props changed) Log: turn these into packages, fix the testing among other tests problems. Added: pypy/dist/pypy/lib/logic/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/__init__.py Mon Mar 20 19:17:52 2006 @@ -0,0 +1 @@ +# Added: pypy/dist/pypy/lib/logic/basic_store/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/basic_store/__init__.py Mon Mar 20 19:17:52 2006 @@ -0,0 +1 @@ +# Added: pypy/dist/pypy/lib/logic/computation_space/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/logic/computation_space/__init__.py Mon Mar 20 19:17:52 2006 @@ -0,0 +1 @@ +# From cfbolz at codespeak.net Mon Mar 20 19:26:53 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 19:26:53 +0100 (CET) Subject: [pypy-svn] r24637 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20060320182653.38ABC100EA@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 19:26:51 2006 New Revision: 24637 Modified: pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/backendopt/test/test_inline.py Log: add a switch to the inliner, which will try very hard to also inline calls that are exception guarded. The transformation stays valid (no wrong code is produced), but potentially big graphs can be the result. Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Mon Mar 20 19:26:51 2006 @@ -2,6 +2,7 @@ from pypy.translator.simplify import eliminate_empty_blocks, join_blocks from pypy.translator.simplify import remove_identical_vars, get_graph from pypy.translator.unsimplify import copyvar, split_block +from pypy.translator.backendopt import canraise from pypy.objspace.flow.model import Variable, Constant, Block, Link from pypy.objspace.flow.model import SpaceOperation, c_last_exception from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph @@ -87,16 +88,35 @@ return None, None return ops[-4].args[2].value, block.exits[0] +def does_raise_directly(graph, raise_analyzer): + """ this function checks, whether graph contains operations which can raise + and which are not exception guarded """ + for block in graph.iterblocks(): + if block.exitswitch == c_last_exception: + consider_ops_to = -1 + else: + consider_ops_to = len(block.operations) + for op in block.operations[:consider_ops_to]: + if raise_analyzer.can_raise(op): + return True + return False class Inliner(object): - def __init__(self, translator, graph, inline_func): + def __init__(self, translator, graph, inline_func, inline_guarded_calls=False): self.translator = translator self.graph = graph self.inline_func = inline_func callsites = find_callsites(graph, inline_func) + # to simplify exception matching + join_blocks(graph) self.block_to_index = {} for g, block, i in callsites: self.block_to_index.setdefault(block, {})[i] = g + self.inline_guarded_calls = inline_guarded_calls + if inline_guarded_calls: + self.raise_analyzer = canraise.RaiseAnalyzer(translator) + else: + self.raise_analyzer = None def inline_all(self): count = 0 @@ -130,8 +150,11 @@ if (block.exitswitch == c_last_exception and index_operation == len(block.operations) - 1): self.exception_guarded = True - if len(collect_called_graphs(self.graph_to_inline, self.translator)) != 0: - raise CannotInline("can't handle exceptions yet") + if self.inline_guarded_calls: + if does_raise_directly(self.graph_to_inline, self.raise_analyzer): + raise CannotInline("can't inline because the call is exception guarded") + elif len(collect_called_graphs(self.graph_to_inline, self.translator)) != 0: + raise CannotInline("can't handle exceptions") self._passon_vars = {} self.entrymap = mkentrymap(self.graph_to_inline) self.do_inline(block, index_operation) @@ -265,6 +288,7 @@ self.rewire_exceptblock_with_guard(afterblock, copiedexceptblock) # generate blocks that do generic matching for cases when the # heuristic did not work +# self.translator.view() self.generic_exception_matching(afterblock, copiedexceptblock) def rewire_exceptblock_no_guard(self, afterblock, copiedexceptblock): Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_inline.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_inline.py Mon Mar 20 19:26:51 2006 @@ -4,7 +4,7 @@ from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant from pypy.objspace.flow.model import last_exception, checkgraph from pypy.translator.backendopt.inline import inline_function, CannotInline -from pypy.translator.backendopt.inline import auto_inlining +from pypy.translator.backendopt.inline import auto_inlining, Inliner from pypy.translator.backendopt.inline import collect_called_graphs from pypy.translator.backendopt.inline import measure_median_execution_cost from pypy.translator.translator import TranslationContext, graphof @@ -43,13 +43,19 @@ t.buildrtyper().specialize() return t -def check_inline(func, in_func, sig, entry=None): +def check_inline(func, in_func, sig, entry=None, inline_guarded_calls=False): if entry is None: entry = in_func t = translate(entry, sig) # inline! sanity_check(t) # also check before inlining (so we don't blame it) - inline_function(t, func, graphof(t, in_func)) + if option.view: + t.view() + inliner = Inliner(t, graphof(t, in_func), func, inline_guarded_calls) + inliner.inline_all() +# inline_function(t, func, graphof(t, in_func)) + if option.view: + t.view() sanity_check(t) interp = LLInterpreter(t.rtyper) def eval_func(args): @@ -170,6 +176,34 @@ result = eval_func([42]) assert result == 1 +def test_inline_exception_guarded(): + def h(x): + if x == 1: + raise ValueError() + elif x == 2: + raise TypeError() + return 1 + def f(x): + try: + return h(x) + except: + raise + def g(x): + try: + f(x) + except ValueError: + return 2 + except TypeError: + return 3 + return 1 + eval_func = check_inline(f, g, [int], inline_guarded_calls=True) + result = eval_func([0]) + assert result == 1 + result = eval_func([1]) + assert result == 2 + result = eval_func([2]) + assert result == 3 + def test_inline_var_exception(): def f(x): e = None @@ -434,3 +468,5 @@ if option.view: t.view() assert hasattr(ggraph.startblock.operations[0], "cleanup") + + From cfbolz at codespeak.net Mon Mar 20 20:17:16 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 20 Mar 2006 20:17:16 +0100 (CET) Subject: [pypy-svn] r24640 - in pypy/dist/pypy/rpython/memory: . test Message-ID: <20060320191716.27044100EF@code0.codespeak.net> Author: cfbolz Date: Mon Mar 20 20:17:14 2006 New Revision: 24640 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: reverted checkin r24534 since it broke tests translator/c/test_newgc.py and translator/c/test_extfunc.py. No gc(un)protect gets exception handling attached again, this will have to be fixed after the refactoring of the gc transformer. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Mon Mar 20 20:17:14 2006 @@ -103,9 +103,9 @@ # seem to run into all the same problems as the ones we already # had to solve there. has_exception_handler = block.exitswitch == c_last_exception - for i, origop in enumerate(block.operations): + for i, op in enumerate(block.operations): num_ops_after_exc_raising = 0 - res = self.replacement_operations(origop, livevars, block) + res = self.replacement_operations(op, livevars, block) try: ops, cleanup_before_exception = res except ValueError: @@ -113,16 +113,17 @@ if not ops: continue # may happen when we eat gc_protect/gc_unprotect. newops.extend(ops) + origname = op.opname op = ops[-1-num_ops_after_exc_raising] # look into the table of all operations to check whether op is # expected to raise. if it is not in the table or the last # operation in a block with exception catching, we assume it can if (op.opname not in LL_OPERATIONS or + op.opname not in NEVER_RAISING_OPS or (has_exception_handler and i == len(block.operations) - 1)): can_raise = True else: - can_raise = (LL_OPERATIONS[op.opname].canraise and - origop.opname not in NEVER_RAISING_OPS) + can_raise = bool(LL_OPERATIONS[op.opname].canraise) if can_raise: if tuple(livevars) in livevars2cleanup: cleanup_on_exception = livevars2cleanup[tuple(livevars)] Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Mon Mar 20 20:17:14 2006 @@ -253,7 +253,7 @@ has_cleanup = False ops = getops(graphof(t, f)) for op in ops.get('direct_call', []): - assert not op.cleanup + assert op.cleanup is None or op.cleanup == ((), ()) # end of protection tests From nik at codespeak.net Mon Mar 20 21:20:08 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 20 Mar 2006 21:20:08 +0100 (CET) Subject: [pypy-svn] r24645 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060320202008.7C7C710041@code0.codespeak.net> Author: nik Date: Mon Mar 20 21:20:01 2006 New Revision: 24645 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: some form of exception support for gensqueak. this needs more tests and some tidying up. Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Mon Mar 20 21:20:01 2006 @@ -104,6 +104,8 @@ return str(value) elif isinstance(value, ootype._class): return self.format_Instance(value._INSTANCE) + elif isinstance(value, ootype._instance): + return self.format_Instance(value._TYPE) elif isinstance(value, ootype._static_meth): return self.gen.unique_func_name(value.graph) else: @@ -112,7 +114,8 @@ def format_Instance(self, INSTANCE): if INSTANCE is None: return "Object" - return self.gen.unique_class_name(INSTANCE) + else: + return self.gen.unique_class_name(INSTANCE) def format_Self(self, _): return "self" Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Mon Mar 20 21:20:01 2006 @@ -1,9 +1,9 @@ import datetime -from pypy.objspace.flow.model import Constant, Variable +from pypy.objspace.flow.model import Constant, Variable, c_last_exception from pypy.translator.squeak.opformatter import OpFormatter from pypy.translator.squeak.codeformatter import CodeFormatter, Message from pypy.translator.squeak.codeformatter import Field, Assignment, CustomVariable -from pypy.rpython.ootypesystem.ootype import Instance, ROOT +from pypy.rpython.ootypesystem.ootype import Instance, Class, ROOT class CodeNode: @@ -21,25 +21,30 @@ class ClassNode(CodeNode): - def __init__(self, gen, INSTANCE, class_vars=None): + def __init__(self, gen, INSTANCE, class_vars=None, host_base=None): self.gen = gen self.INSTANCE = INSTANCE self.class_vars = [] # XXX should probably go away if class_vars is not None: self.class_vars = class_vars + self.host_base = host_base self.hash_key = INSTANCE def dependencies(self): deps = [] - if self.INSTANCE._superclass is not None: # not root + if self.INSTANCE._superclass is not None \ + and self.host_base is None: # not root deps.append(ClassNode(self.gen, self.INSTANCE._superclass)) return deps def render(self): codef = CodeFormatter(self.gen) - yield "%s subclass: #%s" % ( - codef.format_Instance(self.INSTANCE._superclass), - codef.format_Instance(self.INSTANCE)) + if self.host_base is None: + superclass = codef.format_Instance(self.INSTANCE._superclass) + else: + superclass = self.host_base + yield "%s subclass: #%s" % \ + (superclass, codef.format_Instance(self.INSTANCE)) fields = [self.gen.unique_field_name(self.INSTANCE, f) for f in self.INSTANCE._fields.iterkeys()] yield " instanceVariableNames: '%s'" % ' '.join(fields) @@ -74,6 +79,12 @@ class CallableNode(CodeNode): + OPERATION_ERROR = Instance("OperationError", ROOT, + fields={"type": Class, "value": ROOT}) + + def dependencies(self): + return [ClassNode(self.gen, self.OPERATION_ERROR, host_base="Exception")] + def render_body(self, startblock): self.codef = CodeFormatter(self.gen) self.loops = LoopFinder(startblock).loops @@ -89,14 +100,19 @@ def render_return(self, args): if len(args) == 2: # exception - exc_cls = self.codef.format(args[0]) - exc_val = self.codef.format(args[1]) - yield "(PyOperationError class: %s value: %s) signal." % (exc_cls, exc_val) + yield self.render_exception(args[0], args[1]) else: # regular return block retval = self.codef.format(args[0]) yield "^%s" % retval + def render_exception(self, exception_class, exception_value): + exc_cls = self.codef.format(exception_class) + exc_val = self.codef.format(exception_value) + return "((%s new) type: %s; value: %s) signal." \ + % (self.codef.format_Instance(self.OPERATION_ERROR), + exc_cls, exc_val) + def render_link(self, link): block = link.target if link.args: @@ -113,6 +129,8 @@ yield '"skip1"' return yield "[" + if block.exitswitch is c_last_exception: + yield "[" formatter = OpFormatter(self.gen, self) for op in block.operations: yield "%s." % formatter.format(op) @@ -125,6 +143,30 @@ assert len(block.exits) == 1 for line in self.render_link(block.exits[0]): yield line + elif block.exitswitch is c_last_exception: + # exception branching + # wuah. ugly! + exc_var = self.gen.unique_name(("var", "exception"), "exception") + yield "] on: %s do: [:%s |" \ + % (formatter.codef.format(self.OPERATION_ERROR), exc_var) + exc_exits = [] + non_exc_exit = None + for exit in block.exits: + if exit.exitcase is None: + non_exc_exit = exit + else: + exc_exits.append(exit) + for exit in exc_exits: + yield "(%s type isKindOf: %s) ifTrue: [" \ + % (exc_var, formatter.codef.format(exit.llexitcase)) + for line in self.render_link(exit): + yield line + yield "] ifFalse: [" + for exit in exc_exits: + yield "]" + yield "]." + for line in self.render_link(non_exc_exit): + yield line else: #exitswitch if self.loops.has_key(block): @@ -157,7 +199,8 @@ self.hash_key = (INSTANCE, method_name) def dependencies(self): - return [ClassNode(self.gen, self.INSTANCE)] + return CallableNode.dependencies(self) \ + + [ClassNode(self.gen, self.INSTANCE)] def arguments(self, startblock): # Omit the explicit self @@ -185,7 +228,8 @@ self.hash_key = graph def dependencies(self): - return [ClassNode(self.gen, self.FUNCTIONS)] + return CallableNode.dependencies(self) \ + + [ClassNode(self.gen, self.FUNCTIONS)] def arguments(self, startblock): return startblock.inputargs @@ -215,8 +259,9 @@ def render(self): yield self.render_fileout_header( self.codef.format(self.INSTANCE), "accessors") - yield "%s: value" % self.unique_name - yield " %s := value" % self.unique_name + arg_name = self.gen.unique_name((SetterNode, "arg"), "value") + yield "%s: %s" % (self.unique_name, arg_name) + yield " %s := %s" % (self.unique_name, arg_name) yield "! !" class GetterNode(AccessorNode): Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Mon Mar 20 21:20:01 2006 @@ -156,6 +156,7 @@ return Assignment(op.result, op.args[0]) op_oodowncast = noop + op_ooupcast = noop def op_direct_call(self, op): # XXX how do i get rid of this import? Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Mon Mar 20 21:20:01 2006 @@ -141,3 +141,18 @@ assert fn(1) == "1" assert fn(2) == "2" + def test_simpleexception(self): + def raising(i): + if i > 0: + raise ValueError + else: + return i + 1 + def f(i): + try: + return raising(i) + except ValueError, val: + return i - 1 + fn = compile_function(f, [int]) + assert fn(-1) == "0" + assert fn(2) == "1" + From arigo at codespeak.net Mon Mar 20 22:09:23 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Mar 2006 22:09:23 +0100 (CET) Subject: [pypy-svn] r24646 - in pypy/dist/pypy/jit: . test Message-ID: <20060320210923.DFE7910101@code0.codespeak.net> Author: arigo Date: Mon Mar 20 22:09:22 2006 New Revision: 24646 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: Intermediate check-in with skipped tests: detect degenerated virtual containers. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Mon Mar 20 22:09:22 2006 @@ -103,6 +103,7 @@ if isinstance(hop.args_r[0], BlueRepr): return hop.args_r[0].timeshift_getfield(hop) # non virtual case + # XXX green getfields on an immutable structure could be more efficient ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) RESTYPE = originalconcretetype(hop.s_result) @@ -123,6 +124,7 @@ ts.s_RedBox) def translate_op_getarrayitem(self, hop): + # XXX green getarrayitems on an immutable array could be more efficient ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) RESTYPE = originalconcretetype(hop.s_result) @@ -147,10 +149,7 @@ raise NotImplementedError def translate_op_getsubstruct(self, hop): - if isinstance(hop.args_r[0], BlueRepr): - return hop.args_r[0].timeshift_getsubstruct(hop) - # non virtual case ... - raise NotImplementedError + return hop.args_r[0].timeshift_getsubstruct(hop) def translate_op_malloc(self, hop): r_result = hop.r_result @@ -211,13 +210,20 @@ class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractContainer)): def rtyper_makerepr((ts, hs_container), hrtyper): - assert isinstance(hs_container.contentdef, hintcontainer.VirtualStructDef) - return BlueStructRepr(hs_container.concretetype, hs_container.contentdef, + vstructdef = hs_container.contentdef + assert isinstance(vstructdef, hintcontainer.VirtualStructDef) + if vstructdef.degenerated: + # fall back to a red repr + return hrtyper.getredrepr(hs_container.concretetype) + return BlueStructRepr(hs_container.concretetype, vstructdef, hrtyper.timeshifter) def rtyper_makekey((ts, hs_container), hrtyper): - assert isinstance(hs_container.contentdef, hintcontainer.VirtualStructDef) vstructdef = hs_container.contentdef + assert isinstance(vstructdef, hintcontainer.VirtualStructDef) + if vstructdef.degenerated: + # fall back to a red repr + return hs_container.__class__, "red", hs_container.concretetype # compute reconstruction information up to our top-most parent chain = [vstructdef.T] @@ -270,6 +276,10 @@ def residual_values(self, ll_value): return [ll_value] + def create(self, hop): + XXX #... + + class BlueRepr(Repr): pass @@ -430,6 +440,9 @@ def residual_values(self, ll_value): return [] + #def timeshift_getsubstruct(self, hop): + # ... + green_signed_repr = GreenRepr(lltype.Signed) green_void_repr = GreenRepr(lltype.Void) Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Mon Mar 20 22:09:22 2006 @@ -8,14 +8,15 @@ from pypy.jit.test.test_llabstractinterp import annotation, summary from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.objectmodel import hint -from pypy.rpython import rgenop +from pypy.rpython import rgenop, rstr from pypy.annotation import model as annmodel from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph +from pypy.translator.backendopt.inline import auto_inlining from pypy import conftest -def hannotate(func, values, policy=None): +def hannotate(func, values, policy=None, inline=None): # build the normal ll graphs for ll_function t = TranslationContext() a = t.buildannotator() @@ -23,6 +24,8 @@ a.build_types(func, argtypes) rtyper = t.buildrtyper() rtyper.specialize() + if inline: + auto_inlining(t, inline) graph1 = graphof(t, func) # build hint annotator types hannotator = HintAnnotator(policy=policy) @@ -34,8 +37,8 @@ hannotator.translator.view() return hs, hannotator, rtyper -def timeshift(ll_function, values, opt_consts=[]): - hs, ha, rtyper = hannotate(ll_function, values) +def timeshift(ll_function, values, opt_consts=[], inline=None): + hs, ha, rtyper = hannotate(ll_function, values, inline=inline) htshift = HintTimeshift(ha, rtyper) htshift.timeshift() t = rtyper.annotator.translator @@ -316,3 +319,40 @@ insns, res = timeshift(ll_function, [7], [0]) assert res == 7 assert insns == {} + +def test_merge_substructure(): + py.test.skip("in-progress") + S = lltype.GcStruct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) + + def ll_function(flag): + t = lltype.malloc(T) + t.s.n = 3 + s = lltype.malloc(S) + s.n = 4 + if flag: + s = t.s + return s + insns, res = timeshift(ll_function, [0], []) + assert res.n == 4 + assert insns == {'malloc': 1, 'setfield': 1, 'getfield': 1} + +def test_plus_minus_all_inlined(): + py.test.skip("in-progress") + def ll_plus_minus(s, x, y): + acc = x + n = len(s) + pc = 0 + while pc < n: + op = s[pc] + op = hint(op, concrete=True) + if op == '+': + acc += y + elif op == '-': + acc -= y + pc += 1 + return acc + s = rstr.string_repr.convert_const("+-+") + insns, res = timeshift(ll_plus_minus, [s, 0, 2], [0], inline=999) + assert res == ll_plus_minus(s, 0, 2) + assert insns == {'int_add': 2, 'int_sub': 1} From pedronis at codespeak.net Mon Mar 20 23:15:22 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 23:15:22 +0100 (CET) Subject: [pypy-svn] r24648 - pypy/dist/pypy/rpython Message-ID: <20060320221522.B229510118@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 23:15:21 2006 New Revision: 24648 Modified: pypy/dist/pypy/rpython/llinterp.py Log: don't use _instance directly. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Mon Mar 20 23:15:21 2006 @@ -123,6 +123,8 @@ def checkadr(addr): return lltype.typeOf(addr) == llmemory.Address +def checkinst(inst): + return isinstance(lltype.typeOf(inst), ootype.Instance) class LLFrame(object): def __init__(self, graph, args, llinterpreter, f_back=None): @@ -793,19 +795,19 @@ return ootype.runtimenew(class_) def op_oosetfield(self, inst, name, value): - assert isinstance(inst, ootype._instance) + assert checkinst(inst) assert isinstance(name, str) FIELDTYPE = lltype.typeOf(inst)._field_type(name) if FIELDTYPE != lltype.Void: setattr(inst, name, value) def op_oogetfield(self, inst, name): - assert isinstance(inst, ootype._instance) + assert checkinst(inst) assert isinstance(name, str) return getattr(inst, name) def op_oosend(self, message, inst, *args): - assert isinstance(inst, ootype._instance) + assert checkinst(inst) assert isinstance(message, str) bm = getattr(inst, message) m = bm.meth @@ -821,12 +823,12 @@ return ootype.oodowncast(INST, inst) def op_oononnull(self, inst): - assert isinstance(inst, ootype._instance) + assert checkinst(inst) return bool(inst) def op_oois(self, obj1, obj2): - if isinstance(obj1, ootype._instance): - assert isinstance(obj2, ootype._instance) + if checkinst(obj1): + assert checkinst(obj2) return obj1 == obj2 # NB. differently-typed NULLs must be equal elif isinstance(obj1, ootype._class): assert isinstance(obj2, ootype._class) From pedronis at codespeak.net Mon Mar 20 23:43:53 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Mar 2006 23:43:53 +0100 (CET) Subject: [pypy-svn] r24651 - pypy/dist/pypy/rpython Message-ID: <20060320224353.8FF2B1011E@code0.codespeak.net> Author: pedronis Date: Mon Mar 20 23:43:52 2006 New Revision: 24651 Modified: pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/typesystem.py Log: now isCompatibleType work by delegation directly. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Mon Mar 20 23:43:52 2006 @@ -155,7 +155,7 @@ def setvar(self, var, val): if var.concretetype is not lltype.Void: - assert self.llinterpreter.typer.type_system.isCompatibleType(lltype.typeOf(val), var.concretetype) + assert lltype.isCompatibleType(lltype.typeOf(val), var.concretetype) assert isinstance(var, Variable) self.bindings[var] = val @@ -169,7 +169,7 @@ except AttributeError: val = self.bindings[varorconst] if varorconst.concretetype is not lltype.Void: - assert self.llinterpreter.typer.type_system.isCompatibleType(lltype.typeOf(val), varorconst.concretetype) + assert lltype.isCompatibleType(lltype.typeOf(val), varorconst.concretetype) return val # _______________________________________________________ Modified: pypy/dist/pypy/rpython/typesystem.py ============================================================================== --- pypy/dist/pypy/rpython/typesystem.py (original) +++ pypy/dist/pypy/rpython/typesystem.py Mon Mar 20 23:43:52 2006 @@ -92,9 +92,6 @@ def null_callable(self, T): return lltype.nullptr(T.TO) - def isCompatibleType(self, t1, t2): - return lltype.isCompatibleType(t1, t2) - def generic_is(self, robj1, robj2, hop): roriginal1 = robj1 roriginal2 = robj2 @@ -124,9 +121,6 @@ def null_callable(self, T): return ootype.null(T) - def isCompatibleType(self, t1, t2): - return ootype.isCompatibleType(t1, t2) - def generic_is(self, robj1, robj2, hop): roriginal1 = robj1 roriginal2 = robj2 From cfbolz at codespeak.net Tue Mar 21 00:22:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 21 Mar 2006 00:22:03 +0100 (CET) Subject: [pypy-svn] r24656 - in pypy/dist/pypy/translator: backendopt c c/test Message-ID: <20060320232203.3D6DE100FE@code0.codespeak.net> Author: cfbolz Date: Tue Mar 21 00:21:56 2006 New Revision: 24656 Modified: pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/c/exceptiontransform.py pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Log: make catching of exceptions and raising work. requires an evil hack in the inliner Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Tue Mar 21 00:21:56 2006 @@ -102,7 +102,8 @@ return False class Inliner(object): - def __init__(self, translator, graph, inline_func, inline_guarded_calls=False): + def __init__(self, translator, graph, inline_func, inline_guarded_calls=False, + inline_guarded_calls_no_matter_what=False): self.translator = translator self.graph = graph self.inline_func = inline_func @@ -113,6 +114,9 @@ for g, block, i in callsites: self.block_to_index.setdefault(block, {})[i] = g self.inline_guarded_calls = inline_guarded_calls + # if this argument is set, the inliner will happily produce wrong code! + # it is used by the exception transformation + self.inline_guarded_calls_no_matter_what = inline_guarded_calls_no_matter_what if inline_guarded_calls: self.raise_analyzer = canraise.RaiseAnalyzer(translator) else: @@ -151,7 +155,8 @@ index_operation == len(block.operations) - 1): self.exception_guarded = True if self.inline_guarded_calls: - if does_raise_directly(self.graph_to_inline, self.raise_analyzer): + if (not self.inline_guarded_calls_no_matter_what and + does_raise_directly(self.graph_to_inline, self.raise_analyzer)): raise CannotInline("can't inline because the call is exception guarded") elif len(collect_called_graphs(self.graph_to_inline, self.translator)) != 0: raise CannotInline("can't handle exceptions") Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Tue Mar 21 00:21:56 2006 @@ -1,7 +1,7 @@ -from pypy.translator.unsimplify import split_block -from pypy.translator.backendopt import canraise +from pypy.translator.unsimplify import copyvar, split_block +from pypy.translator.backendopt import canraise, inline from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ - c_last_exception, SpaceOperation, checkgraph + c_last_exception, SpaceOperation, checkgraph, FunctionGraph from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.memory.lladdress import NULL from pypy.rpython import rclass @@ -18,36 +18,94 @@ def error_value(T): if isinstance(T, lltype.Primitive): return Constant(PrimitiveErrorValue[T], T) - elif isinstance(T, Ptr): + elif isinstance(T, lltype.Ptr): return Constant(None, T) assert 0, "not implemented yet" +# dummy functions to make the resulting graphs runnable on the llinterpreter + +class ExcData(object): + exc_type = None + exc_value = None + +def rpyexc_occured(): + return ExcData.exc_type is not None + +def rpyexc_fetch_type(): + return ExcData.exc_type + +def rpyexc_fetch_value(): + return ExcData.exc_value + +def rpyexc_clear(): + ExcData.exc_type = None + ExcData.exc_value = None + +def rpyexc_raise(etype, evalue): + ExcData.exc_type = etype + ExcData.exc_value = evalue + class ExceptionTransformer(object): def __init__(self, translator): self.translator = translator self.raise_analyzer = canraise.RaiseAnalyzer(translator) + self.exc_data = translator.rtyper.getexceptiondata() RPYEXC_OCCURED_TYPE = lltype.FuncType([], lltype.Bool) self.rpyexc_occured_ptr = Constant(lltype.functionptr( - RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", external="C"), + RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", external="C", + neverrraises=True, _callable=rpyexc_occured), lltype.Ptr(RPYEXC_OCCURED_TYPE)) + RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_type) + self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr( + RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", external="C", + neverraises=True, _callable=rpyexc_fetch_type), + lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE)) + RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_value) + self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr( + RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", external="C", + neverraises=True, _callable=rpyexc_fetch_value), + lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE)) + RPYEXC_CLEAR = lltype.FuncType([], lltype.Void) + self.rpyexc_clear_ptr = Constant(lltype.functionptr( + RPYEXC_CLEAR, "RPyClearException", external="C", + neverraises=True, _callable=rpyexc_clear), + lltype.Ptr(RPYEXC_CLEAR)) + RPYEXC_RAISE = lltype.FuncType([self.exc_data.lltype_of_exception_type, + self.exc_data.lltype_of_exception_value], + lltype.Void) + self.rpyexc_raise_ptr = Constant(lltype.functionptr( + RPYEXC_RAISE, "RPyRaiseException", external="C", + neverraises=True, _callable=rpyexc_raise), + lltype.Ptr(RPYEXC_RAISE)) + + def transform_completely(self): + for graph in self.translator.graphs: + self.create_exception_handling(graph) def create_exception_handling(self, graph): """After an exception in a direct_call (or indirect_call), that is not caught by an explicit except statement, we need to reraise the exception. So after this direct_call we need to test if an exception had occurred. If so, we return - from the current graph with an unused value (false/0/0.0/null). + from the current graph with a special value (False/-1/-1.0/null). Because of the added exitswitch we need an additional block. """ - exc_data = self.translator.rtyper.getexceptiondata() for block in list(graph.iterblocks()): #collect the blocks before changing them self.transform_block(graph, block) checkgraph(graph) def transform_block(self, graph, block): - last_operation = len(block.operations)-1 + if block is graph.exceptblock: + self.transform_except_block(graph, block) + return + elif block is graph.returnblock: + return + last_operation = len(block.operations) - 1 if block.exitswitch == c_last_exception: + need_exc_matching = True last_operation -= 1 + else: + need_exc_matching = False for i in range(last_operation, -1, -1): op = block.operations[i] print "considering op", op, i @@ -56,19 +114,105 @@ afterblock = split_block(self.translator, graph, block, i+1) - var_exc_occured = Variable() - var_exc_occured.concretetype = lltype.Bool - - block.operations.append(SpaceOperation("direct_call", [self.rpyexc_occured_ptr], var_exc_occured)) - block.exitswitch = var_exc_occured + var_exc_occured, block = self.gen_exc_checking_var(op, i, block, graph) #non-exception case block.exits[0].exitcase = block.exits[0].llexitcase = False + if need_exc_matching: + if not self.raise_analyzer.can_raise(op): + print "XXX: operation %s cannot raise, but has exception guarding in graph %s" (op, graph) + block.exitswitch = None + block.exits = [block.exits[0]] + else: + self.insert_matching(afterblock, graph) + + def transform_except_block(self, graph, block): + # attach an except block -- let's hope that nobody uses it + graph.exceptblock = Block([Variable('etype'), # exception class + Variable('evalue')]) # exception value + result = Variable() + result.concretetype = lltype.Void + block.operations = [SpaceOperation( + "direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result)] + l = Link([error_value(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) + l.prevblock = block + block.exits = [l] + + def insert_matching(self, block, graph): + proxygraph, op = self.create_proxy_graph(block.operations[-1]) + block.operations[-1] = op + #non-exception case + block.exits[0].exitcase = block.exits[0].llexitcase = None + # use the dangerous second True flag :-) + inliner = inline.Inliner(self.translator, graph, proxygraph, True, True) + inliner.inline_all() + block.exits[0].exitcase = block.exits[0].llexitcase = False + + def create_proxy_graph(self, op): + """ creates a graph which calls the original function, checks for + raised exceptions, fetches and then raises them again. If this graph is + inlined, the correct exception matching blocks are produced.""" + # XXX slightly annoying: construct a graph by hand + # but better than the alternative + result = copyvar(self.translator, op.result) + opargs = [] + inputargs = [] + callargs = [] + ARGTYPES = [] + for var in op.args: + if isinstance(var, Variable): + v = Variable() + v.concretetype = var.concretetype + inputargs.append(v) + opargs.append(v) + callargs.append(var) + ARGTYPES.append(var.concretetype) + else: + opargs.append(var) + newop = SpaceOperation(op.opname, opargs, result) + startblock = Block(inputargs) + startblock.operations.append(newop) + newgraph = FunctionGraph("dummy", startblock) + startblock.closeblock(Link([result], newgraph.returnblock)) + startblock.exits = list(startblock.exits) + newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype + var_exc_occured, block = self.gen_exc_checking_var(newop, 0, startblock, newgraph) + startblock.exits[0].exitcase = startblock.exits[0].llexitcase = False + excblock = Block([]) + var_value = Variable() + var_value.concretetype = self.exc_data.lltype_of_exception_value + var_type = Variable() + var_type.concretetype = self.exc_data.lltype_of_exception_type + var_void = Variable() + var_void.concretetype = lltype.Void + excblock.operations.append(SpaceOperation( + "direct_call", [self.rpyexc_fetch_value_ptr], var_value)) + excblock.operations.append(SpaceOperation( + "direct_call", [self.rpyexc_fetch_type_ptr], var_type)) + excblock.operations.append(SpaceOperation( + "direct_call", [self.rpyexc_clear_ptr], var_void)) + newgraph.exceptblock.inputargs[0].concretetype = self.exc_data.lltype_of_exception_type + newgraph.exceptblock.inputargs[1].concretetype = self.exc_data.lltype_of_exception_value + excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) + block.exits[True].target = excblock + block.exits[True].args = [] + FUNCTYPE = lltype.FuncType(ARGTYPES, op.result.concretetype) + fptr = Constant(lltype.functionptr(FUNCTYPE, "dummy", graph=newgraph), + lltype.Ptr(FUNCTYPE)) + self.translator.graphs.append(newgraph) + return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) + + def gen_exc_checking_var(self, op, i, block, graph): + var_exc_occured = Variable() + var_exc_occured.concretetype = lltype.Bool + + block.operations.append(SpaceOperation("direct_call", [self.rpyexc_occured_ptr], var_exc_occured)) + block.exitswitch = var_exc_occured + #exception occurred case + l = Link([error_value(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) + l.prevblock = block + l.exitcase = l.llexitcase = True - #exception occurred case - l = Link([error_value(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) - l.prevblock = block - l.exitcase = l.llexitcase = True - - block.exits.append(l) + block.exits.append(l) + return var_exc_occured, block Modified: pypy/dist/pypy/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Tue Mar 21 00:21:56 2006 @@ -1,6 +1,8 @@ from pypy.translator.translator import TranslationContext, graphof +from pypy.translator.simplify import join_blocks from pypy.translator.c import exceptiontransform from pypy.objspace.flow.model import c_last_exception +from pypy.rpython.test.test_llinterp import get_interpreter from pypy import conftest @@ -13,22 +15,36 @@ g = graphof(t, fn) etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.create_exception_handling(g) + join_blocks(g) if conftest.option.view: t.view() return t, g +_already_transformed = {} + +def interpret(func, values): + interp, graph = get_interpreter(func, values) + t = interp.typer.annotator.translator + if t not in _already_transformed: + etrafo = exceptiontransform.ExceptionTransformer(t) + etrafo.transform_completely() + _already_transformed[t] = True + return interp.eval_graph(graph, values) + def test_simple(): def one(): return 1 def foo(): one() - one() + return one() t, g = transform_func(foo, []) assert len(list(g.iterblocks())) == 2 # graph does not change + result = interpret(foo, []) + assert result == 1 -def test_raises(): +def test_passthrough(): def one(x): if x: raise ValueError() @@ -39,3 +55,40 @@ t, g = transform_func(foo, []) assert len(list(g.iterblocks())) == 4 +def test_catches(): + def one(x): + if x == 1: + raise ValueError() + elif x == 2: + raise TypeError() + return x - 5 + + def foo(x): + x = one(x) + try: + x = one(x) + except ValueError: + return 1 + x + except TypeError: + return 2 + x + except: + return 3 + x + return 4 + x + t, g = transform_func(foo, [int]) + assert len(list(g.iterblocks())) == 9 + result = interpret(foo, [6]) + assert result == 2 + result = interpret(foo, [7]) + assert result == 4 + result = interpret(foo, [8]) + assert result == 2 + + +def test_raises(): + def foo(x): + if x: + raise ValueError() + t, g = transform_func(foo, [int]) + assert len(list(g.iterblocks())) == 4 + + From cfbolz at codespeak.net Tue Mar 21 00:58:13 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 21 Mar 2006 00:58:13 +0100 (CET) Subject: [pypy-svn] r24660 - in pypy/dist/pypy/translator/c: . src test Message-ID: <20060320235813.D79351010C@code0.codespeak.net> Author: cfbolz Date: Tue Mar 21 00:58:12 2006 New Revision: 24660 Modified: pypy/dist/pypy/translator/c/exceptiontransform.py pypy/dist/pypy/translator/c/src/exception.h pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Log: the transformed graphs compile, but the functions segfault in strange ways :-(. I have a feeling that there is a strange interaction with the conversion to real CPython exceptions. Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Tue Mar 21 00:58:12 2006 @@ -19,7 +19,7 @@ if isinstance(T, lltype.Primitive): return Constant(PrimitiveErrorValue[T], T) elif isinstance(T, lltype.Ptr): - return Constant(None, T) + return Constant(lltype.nullptr(T.TO), T) assert 0, "not implemented yet" # dummy functions to make the resulting graphs runnable on the llinterpreter Modified: pypy/dist/pypy/translator/c/src/exception.h ============================================================================== --- pypy/dist/pypy/translator/c/src/exception.h (original) +++ pypy/dist/pypy/translator/c/src/exception.h Tue Mar 21 00:58:12 2006 @@ -33,6 +33,17 @@ rpython_exc_value = NULL; \ } while (0) +#define RPyFetchExceptionValue() rpython_exc_value + +#define RPyFetchExceptionType() rpython_exc_type + +#define RPyClearException() do { \ + rpython_exc_type = NULL; \ + rpython_exc_value = NULL; \ + } while (0) + + + #define RPyMatchException(etype) RPYTHON_EXCEPTION_MATCH(rpython_exc_type, \ (RPYTHON_EXCEPTION_VTABLE) etype) Modified: pypy/dist/pypy/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/test/test_exceptiontransform.py Tue Mar 21 00:58:12 2006 @@ -1,9 +1,10 @@ +import py from pypy.translator.translator import TranslationContext, graphof from pypy.translator.simplify import join_blocks -from pypy.translator.c import exceptiontransform +from pypy.translator.c import exceptiontransform, genc, gc from pypy.objspace.flow.model import c_last_exception from pypy.rpython.test.test_llinterp import get_interpreter - +from pypy.translator.tool.cbuild import skip_missing_compiler from pypy import conftest def transform_func(fn, inputtypes): @@ -30,6 +31,20 @@ etrafo.transform_completely() _already_transformed[t] = True return interp.eval_graph(graph, values) + +def compile_func(fn, inputtypes): + t = TranslationContext() + t.buildannotator().build_types(fn, inputtypes) + t.buildrtyper().specialize() + etrafo = exceptiontransform.ExceptionTransformer(t) + etrafo.transform_completely() + builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.RefcountingGcPolicy) + builder.generate_source() + skip_missing_compiler(builder.compile) + builder.import_module() + if conftest.option.view: + t.view() + return builder.get_entry_point() def test_simple(): def one(): @@ -43,6 +58,8 @@ assert len(list(g.iterblocks())) == 2 # graph does not change result = interpret(foo, []) assert result == 1 + f = compile_func(foo, []) +# assert f() == 1 def test_passthrough(): def one(x): @@ -54,6 +71,8 @@ one(1) t, g = transform_func(foo, []) assert len(list(g.iterblocks())) == 4 + f = compile_func(foo, []) +# py.test.raises(ValueError, f) def test_catches(): def one(x): @@ -76,12 +95,19 @@ return 4 + x t, g = transform_func(foo, [int]) assert len(list(g.iterblocks())) == 9 + f = compile_func(foo, [int]) result = interpret(foo, [6]) assert result == 2 +# result = f(6) +# assert result == 2 result = interpret(foo, [7]) assert result == 4 +# result = f(7) +# assert result == 4 result = interpret(foo, [8]) assert result == 2 +# result = f(8) +# assert result == 2 def test_raises(): @@ -90,5 +116,7 @@ raise ValueError() t, g = transform_func(foo, [int]) assert len(list(g.iterblocks())) == 4 - + f = compile_func(foo, [int]) +# f(0) +# py.test.raises(ValueError, f, 0) From hpk at codespeak.net Tue Mar 21 01:56:20 2006 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 21 Mar 2006 01:56:20 +0100 (CET) Subject: [pypy-svn] r24663 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060321005620.33A3D10116@code0.codespeak.net> Author: hpk Date: Tue Mar 21 01:56:18 2006 New Revision: 24663 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: my two week plan for Leysin - hopefully nothing interfers this time :) I am likely to arrive from Paris on the 1st March evening. Note that i am ok with occupying a room myself because i have been in company day and night for most of the last 5 weeks. Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Tue Mar 21 01:56:18 2006 @@ -12,7 +12,7 @@ Name Arrive/Depart Accomodation ==================== ============== ===================== Anders Chrigstroem 2/3 - 10/3 Ermina -Holger Krekel ? Ermina? +Holger Krekel 1st - 14 Ermina Samuele Pedroni 2/3 - 10/3 Ermina Armin Rigo -- private Christian Tismer ? Ermina? From pedronis at codespeak.net Tue Mar 21 03:03:31 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 03:03:31 +0100 (CET) Subject: [pypy-svn] r24665 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/ootypesystem rpython/ootypesystem/test rpython/test Message-ID: <20060321020331.6E70B100F6@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 03:03:23 2006 New Revision: 24665 Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/rootype.py pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py pypy/dist/pypy/rpython/test/test_rclass.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: make ootype enforce static types with views, casts aren't noops anymore. add and update tests. llinterp uses now enforce helper which can upcast as necessary. (for now one can get back the previous dynamic behavior by changing a flag) shouldn't break gensqueak too much. Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Tue Mar 21 03:03:23 2006 @@ -380,7 +380,7 @@ result = SomeOOStaticMeth(ootype.typeOf(x)) elif isinstance(x, ootype._class): result = SomeOOClass(x._INSTANCE) # NB. can be None - elif isinstance(x, ootype._instance): + elif isinstance(x, ootype.instance_impl): # XXX result = SomeOOInstance(ootype.typeOf(x)) elif callable(x): if hasattr(x, '__self__') and x.__self__ is not None: Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Tue Mar 21 03:03:23 2006 @@ -155,7 +155,10 @@ def setvar(self, var, val): if var.concretetype is not lltype.Void: - assert lltype.isCompatibleType(lltype.typeOf(val), var.concretetype) + try: + val = lltype.enforce(var.concretetype, val) + except TypeError: + assert False, "type error: %r val -> %r var" % (lltype.typeOf(val), var.concretetype) assert isinstance(var, Variable) self.bindings[var] = val @@ -169,7 +172,10 @@ except AttributeError: val = self.bindings[varorconst] if varorconst.concretetype is not lltype.Void: - assert lltype.isCompatibleType(lltype.typeOf(val), varorconst.concretetype) + try: + val = lltype.enforce(varorconst.concretetype, val) + except TypeError: + assert False, "type error: %r val from %r var/const" % (lltype.typeOf(val), varorconst.concretetype) return val # _______________________________________________________ @@ -810,8 +816,9 @@ assert checkinst(inst) assert isinstance(message, str) bm = getattr(inst, message) + inst = bm.inst m = bm.meth - m._checkargs(args, check_callable=False) + args = m._checkargs(args, check_callable=False) if getattr(m, 'abstract', False): raise RuntimeError("calling abstract method %r" % (m,)) return self.op_direct_call(m, inst, *args) Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Tue Mar 21 03:03:23 2006 @@ -66,6 +66,11 @@ _is_compatible = __eq__ + def _enforce(self, value): + if typeOf(value) != self: + raise TypeError + return value + def __hash__(self): # cannot use saferecursive() -- see test_lltype.test_hash(). # NB. the __cached_hash should neither be used nor updated @@ -1105,7 +1110,9 @@ def isCompatibleType(TYPE1, TYPE2): return TYPE1._is_compatible(TYPE2) - return TYPE1 == TYPE2 + +def enforce(TYPE, value): + return TYPE._enforce(value) # mark type ADT methods Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Tue Mar 21 03:03:23 2006 @@ -1,8 +1,10 @@ from pypy.rpython.lltypesystem.lltype import LowLevelType, Signed, Unsigned, Float, Char from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \ - Primitive, isCompatibleType + Primitive, isCompatibleType, enforce from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType +STATICNESS = True + class OOType(LowLevelType): def _is_compatible(TYPE1, TYPE2): @@ -13,6 +15,16 @@ else: return False + def _enforce(TYPE2, value): + TYPE1 = typeOf(value) + if TYPE1 == TYPE2: + return value + if isinstance(TYPE1, Instance) and isinstance(TYPE2, Instance): + if isSubclass(TYPE1, TYPE2): + return value._enforce(TYPE2) + raise TypeError + + class Class(OOType): def _defl(self): @@ -38,7 +50,7 @@ self._add_fields(fields) self._add_methods(methods) - self._null = _null_instance(self) + self._null = make_null_instance(self) self._class = _class(self) def _defl(self): @@ -55,7 +67,8 @@ def _add_fields(self, fields): fields = fields.copy() # mutated below for name, defn in fields.iteritems(): - if self._lookup(name) is not None: + _, meth = self._lookup(name) + if meth is not None: raise TypeError("Cannot add field %r: method already exists" % name) if self._superclass is not None: @@ -95,7 +108,7 @@ self._superclass._init_instance(instance) for name, (ootype, default) in self._fields.iteritems(): - instance.__dict__[name] = default + instance.__dict__[name] = enforce(ootype, default) def _has_field(self, name): try: @@ -122,9 +135,9 @@ meth = self._methods.get(meth_name) if meth is None and self._superclass is not None: - meth = self._superclass._lookup(meth_name) + return self._superclass._lookup(meth_name) - return meth + return self, meth def _allfields(self): if self._superclass is None: @@ -171,9 +184,9 @@ INSTANCE._init_instance(self) def __getattr__(self, name): - meth = self._TYPE._lookup(name) + DEFINST, meth = self._TYPE._lookup(name) if meth is not None: - return meth._bound(self) + return meth._bound(DEFINST, self) self._TYPE._check_field(name) @@ -181,9 +194,12 @@ def __setattr__(self, name, value): self.__getattr__(name) - - if not isCompatibleType(typeOf(value), self._TYPE._field_type(name)): - raise TypeError("Expected type %r" % self._TYPE._field_type(name)) + + FLDTYPE = self._TYPE._field_type(name) + try: + val = enforce(FLDTYPE, value) + except TypeError: + raise TypeError("Expected type %r" % FLDTYPE) self.__dict__[name] = value @@ -198,6 +214,31 @@ def __ne__(self, other): return not (self == other) + def _instanceof(self, INSTANCE): + assert isinstance(INSTANCE, Instance) + return bool(self) and isSubclass(self._TYPE, INSTANCE) + + def _classof(self): + assert bool(self) + return runtimeClass(self._TYPE) + + def _upcast(self, INSTANCE): + assert instanceof(self, INSTANCE) + return self + + _enforce = _upcast + + def _downcast(self, INSTANCE): + assert instanceof(self, INSTANCE) + return self + + def _identityhash(self): + if self: + return id(self) + else: + return 0 # for all null instances + + class _null_instance(_instance): def __init__(self, INSTANCE): @@ -224,6 +265,74 @@ raise TypeError("comparing an _instance with %r" % (other,)) return not other + +class _view(object): + + def __init__(self, INSTANCE, inst): + self.__dict__['_TYPE'] = INSTANCE + assert isinstance(inst, _instance) + assert isSubclass(inst._TYPE, INSTANCE) + self.__dict__['_inst'] = inst + + def __ne__(self, other): + return not (self == other) + + def __eq__(self, other): + assert isinstance(other, _view) + return self._inst == other._inst + + def __nonzero__(self): + return bool(self._inst) + + def __setattr__(self, name, value): + self._TYPE._check_field(name) + setattr(self._inst, name, value) + + def __getattr__(self, name): + _, meth = self._TYPE._lookup(name) + meth or self._TYPE._check_field(name) + res = getattr(self._inst, name) + if meth: + assert isinstance(res, _bound_meth) + return _bound_meth(res.DEFINST, _view(res.DEFINST, res.inst), res.meth) + return res + + def _instanceof(self, INSTANCE): + return self._inst._instanceof(INSTANCE) + + def _classof(self): + return self._inst._classof() + + def _upcast(self, INSTANCE): + assert isSubclass(self._TYPE, INSTANCE) + return _view(INSTANCE, self._inst) + + _enforce = _upcast + + def _downcast(self, INSTANCE): + assert isSubclass(INSTANCE, self._TYPE) + return _view(INSTANCE, self._inst) + + def _identityhash(self): + return self._inst._identityhash() + +if STATICNESS: + instance_impl = _view +else: + instance_impl = _instance + +def make_instance(INSTANCE): + inst = _instance(INSTANCE) + if STATICNESS: + inst = _view(INSTANCE, inst) + return inst + +def make_null_instance(INSTANCE): + inst = _null_instance(INSTANCE) + if STATICNESS: + inst = _view(INSTANCE, inst) + return inst + class _callable(object): def __init__(self, TYPE, **attrs): @@ -236,15 +345,19 @@ if len(args) != len(self._TYPE.ARGS): raise TypeError,"calling %r with wrong argument number: %r" % (self._TYPE, args) + checked_args = [] for a, ARG in zip(args, self._TYPE.ARGS): - if not isCompatibleType(typeOf(a), ARG): + try: + a = enforce(ARG, a) + except TypeError: raise TypeError,"calling %r with wrong argument types: %r" % (self._TYPE, args) + checked_args.append(a) if not check_callable: - return None + return checked_args callb = self._callable if callb is None: raise RuntimeError,"calling undefined or null function" - return callb + return callb, checked_args def __eq__(self, other): return (self.__class__ is other.__class__ and @@ -264,7 +377,8 @@ _callable.__init__(self, STATICMETHOD, **attrs) def __call__(self, *args): - return self._checkargs(args)(*args) + callb, checked_args = self._checkargs(args) + return callb(*checked_args) class _meth(_callable): @@ -272,24 +386,27 @@ assert isinstance(METHOD, Meth) _callable.__init__(self, METHOD, **attrs) - def _bound(self, inst): - return _bound_meth(inst, self) + def _bound(self, DEFINST, inst): + assert isinstance(inst, _instance) + return _bound_meth(DEFINST, inst, self) class _bound_meth(object): - def __init__(self, inst, meth): + def __init__(self, DEFINST, inst, meth): + self.DEFINST = DEFINST self.inst = inst self.meth = meth def __call__(self, *args): - return self.meth._checkargs(args)(self.inst, *args) + callb, checked_args = self.meth._checkargs(args) + return callb(self.inst, *checked_args) def new(INSTANCE): - return _instance(INSTANCE) + return make_instance(INSTANCE) def runtimenew(class_): assert isinstance(class_, _class) assert class_ is not nullruntimeclass - return _instance(class_._INSTANCE) + return make_instance(class_._INSTANCE) def static_meth(FUNCTION, name, **attrs): return _static_meth(FUNCTION, _name=name, **attrs) @@ -303,14 +420,12 @@ def instanceof(inst, INSTANCE): # this version of instanceof() accepts a NULL instance and always # returns False in this case. - assert isinstance(inst, _instance) - assert isinstance(INSTANCE, Instance) - return bool(inst) and isSubclass(inst._TYPE, INSTANCE) + assert isinstance(typeOf(inst), Instance) + return inst._instanceof(INSTANCE) def classof(inst): - assert isinstance(inst, _instance) - assert bool(inst) - return runtimeClass(inst._TYPE) + assert isinstance(typeOf(inst), Instance) + return inst._classof() def subclassof(class1, class2): assert isinstance(class1, _class) @@ -346,19 +461,14 @@ return None def ooupcast(INSTANCE, instance): - assert instanceof(instance, INSTANCE) - return instance + return instance._upcast(INSTANCE) def oodowncast(INSTANCE, instance): - assert instanceof(instance, INSTANCE) - return instance + return instance._downcast(INSTANCE) def ooidentityhash(inst): - assert isinstance(inst, _instance) - if inst: - return id(inst) - else: - return 0 # for all null instances + assert isinstance(typeOf(inst), Instance) + return inst._identityhash() ROOT = Instance('Root', None, _is_root=True) Modified: pypy/dist/pypy/rpython/ootypesystem/rootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rootype.py Tue Mar 21 03:03:23 2006 @@ -33,7 +33,7 @@ def rtype_getattr(self, hop): attr = hop.args_s[1].const s_inst = hop.args_s[0] - meth = self.lowleveltype._lookup(attr) + _, meth = self.lowleveltype._lookup(attr) if meth is not None: # just return instance - will be handled by simple_call return hop.inputarg(hop.r_result, arg=0) Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py Tue Mar 21 03:03:23 2006 @@ -28,9 +28,9 @@ cls = A return cls() res = interpret(f, [0], type_system='ootype') - assert ootype.typeOf(res)._name.split(".")[-1] == 'A' + assert ootype.classof(res)._INSTANCE._name.split(".")[-1] == 'A' res = interpret(f, [1], type_system='ootype') - assert ootype.typeOf(res)._name.split(".")[-1] == 'B' + assert ootype.classof(res)._INSTANCE._name.split(".")[-1] == 'B' def test_call_classes_init(): class A: Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py Tue Mar 21 03:03:23 2006 @@ -300,3 +300,73 @@ sm = static_meth(SM, 'f', graph='graph') sm1 = static_meth(SM1, 'f', graph='graph') assert sm == sm1 + +def test_casts(): + A = Instance('A', ROOT) + B = Instance('B', A) + b = new(B) + assert instanceof(b, B) + assert instanceof(b, A) + assert typeOf(b) == B + bA = ooupcast(A, b) + assert instanceof(bA, B) + if STATICNESS: + assert typeOf(bA) == A + bB = oodowncast(B, bA) + assert instanceof(bB, A) + assert instanceof(bB, B) + assert typeOf(bB) == B + +def test_visibility(): + if not STATICNESS: + py.test.skip("static types not enforced in ootype") + M = Meth([], Signed) + def mA_(a): + return 1 + def mB_(b): + return 2 + def nB_(b): + return 3 + mA = meth(M, name="m", _callable=mA_) + mB = meth(M, name="m", _callable=mB_) + nB = meth(M, name="n", _callable=nB_) + A = Instance('A', ROOT, {}, {'m': mA}) + B = Instance('B', A, {}, {'m': mB, 'n': nB}) + b = new(B) + assert b.m() == 2 + assert b.n() == 3 + bA = ooupcast(A, b) + assert bA.m() == 2 + py.test.raises(TypeError, "bA.n()") + assert oodowncast(B, bA).n() == 3 + M = Meth([A], Signed) + def xA_(slf, a): + return a.n() + xA = meth(M, name="x", _callable=xA_) + addMethods(A, {'x': xA}) + a = new(A) + py.test.raises(TypeError, "a.x(b)") + def yA_(slf, a): + if instanceof(a, B): + return oodowncast(B, a).n() + return a.m() + yA = meth(M, name="y", _callable=yA_) + addMethods(A, {'y': yA}) + assert a.y(a) == 1 + assert a.y(b) == 3 + # + M = Meth([], Signed) + def zA_(slf): + return slf.n() + zA = meth(M, name="z", _callable=zA_) + addMethods(A, {'z': zA}) + py.test.raises(TypeError, "b.z()") + def zzA_(slf): + if instanceof(slf, B): + return oodowncast(B, slf).n() + return slf.m() + zzA = meth(M, name="zz", _callable=zzA_) + addMethods(A, {'zz': zzA}) + assert a.zz() == 1 + assert b.zz() == 3 + Modified: pypy/dist/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rclass.py (original) +++ pypy/dist/pypy/rpython/test/test_rclass.py Tue Mar 21 03:03:23 2006 @@ -486,7 +486,7 @@ t.buildrtyper(type_system=self.ts).specialize() graph = graphof(t, f) TYPE = graph.startblock.operations[0].args[0].value - meth = TYPE._lookup("o__del___variant0") + _, meth = TYPE._lookup("o__del___variant0") assert meth.finalizer def test_del_inheritance(self): @@ -520,9 +520,9 @@ TYPEA = graph.startblock.operations[0].args[0].value TYPEB = graph.startblock.operations[2].args[0].value TYPEC = graph.startblock.operations[4].args[0].value - destra = TYPEA._lookup("o__del___variant0") - destrb = TYPEB._lookup("o__del___variant0") - destrc = TYPEC._lookup("o__del___variant0") + _, destra = TYPEA._lookup("o__del___variant0") + _, destrb = TYPEB._lookup("o__del___variant0") + _, destrc = TYPEC._lookup("o__del___variant0") assert destra == destrc assert destrb is not None assert destra is not None Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Tue Mar 21 03:03:23 2006 @@ -1381,13 +1381,16 @@ return attr raise AttributeError() +from pypy.rpython.ootypesystem import ootype + class TestOotype(BaseTestRPBC): ts = "ootype" def class_name(self, value): - return typeOf(value)._name.split(".")[-1] + return ootype.classof(value)._INSTANCE._name.split(".")[-1] def read_attr(self, value, attr): + value = ootype.oodowncast(ootype.classof(value)._INSTANCE, value) return getattr(value, "o" + attr) From nik at codespeak.net Tue Mar 21 10:30:39 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 21 Mar 2006 10:30:39 +0100 (CET) Subject: [pypy-svn] r24667 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060321093039.1A52C100F9@code0.codespeak.net> Author: nik Date: Tue Mar 21 10:30:37 2006 New Revision: 24667 Modified: pypy/dist/pypy/translator/squeak/node.py pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Log: make reraising of exceptions uncaught by a try/except work. Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Tue Mar 21 10:30:37 2006 @@ -146,9 +146,10 @@ elif block.exitswitch is c_last_exception: # exception branching # wuah. ugly! + codef = formatter.codef exc_var = self.gen.unique_name(("var", "exception"), "exception") yield "] on: %s do: [:%s |" \ - % (formatter.codef.format(self.OPERATION_ERROR), exc_var) + % (codef.format(self.OPERATION_ERROR), exc_var) exc_exits = [] non_exc_exit = None for exit in block.exits: @@ -158,7 +159,13 @@ exc_exits.append(exit) for exit in exc_exits: yield "(%s type isKindOf: %s) ifTrue: [" \ - % (exc_var, formatter.codef.format(exit.llexitcase)) + % (exc_var, codef.format(exit.llexitcase)) + if exit.last_exception is not None: + yield "%s := %s type." \ + % (codef.format(exit.last_exception), exc_var) + if exit.last_exc_value is not None: + yield "%s := %s value." \ + % (codef.format(exit.last_exc_value), exc_var) for line in self.render_link(exit): yield line yield "] ifFalse: [" Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py Tue Mar 21 10:30:37 2006 @@ -141,6 +141,8 @@ assert fn(1) == "1" assert fn(2) == "2" +class TestException: + def test_simpleexception(self): def raising(i): if i > 0: @@ -156,3 +158,44 @@ assert fn(-1) == "0" assert fn(2) == "1" + def test_exceptbranch(self): + def raising(i): + if i == 0: + raise ValueError + elif i < 0: + raise AttributeError + else: + return i + 1 + def f(i): + try: + return raising(i) + except ValueError: + return i + except AttributeError: + return -i + fn = compile_function(f, [int]) + assert fn(-1) == "1" + assert fn(0) == "0" + assert fn(2) == "3" + + def test_exceptreraise(self): + def raising(i): + if i == 0: + raise ValueError + elif i < 0: + raise AttributeError + else: + return i + 1 + def f(i): + try: + return raising(i) + except ValueError: + return i + def g(i): + try: + return f(i) + except AttributeError: + return -i + fn = compile_function(g, [int]) + assert fn(-2) == "2" + From nik at codespeak.net Tue Mar 21 11:46:16 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 21 Mar 2006 11:46:16 +0100 (CET) Subject: [pypy-svn] r24674 - pypy/dist/pypy/translator/squeak Message-ID: <20060321104616.5E33810116@code0.codespeak.net> Author: nik Date: Tue Mar 21 11:45:53 2006 New Revision: 24674 Modified: pypy/dist/pypy/translator/squeak/codeformatter.py pypy/dist/pypy/translator/squeak/node.py Log: fix initialization of constant instances, broken due to the new static ootype model. it seems like i will need to get the dynamic type out of instances/views a few times, does it make sense to have a method for this on instances/views? Modified: pypy/dist/pypy/translator/squeak/codeformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/codeformatter.py (original) +++ pypy/dist/pypy/translator/squeak/codeformatter.py Tue Mar 21 11:45:53 2006 @@ -104,7 +104,7 @@ return str(value) elif isinstance(value, ootype._class): return self.format_Instance(value._INSTANCE) - elif isinstance(value, ootype._instance): + elif isinstance(value, (ootype._instance, ootype._view)): return self.format_Instance(value._TYPE) elif isinstance(value, ootype._static_meth): return self.gen.unique_func_name(value.graph) Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Tue Mar 21 11:45:53 2006 @@ -3,7 +3,7 @@ from pypy.translator.squeak.opformatter import OpFormatter from pypy.translator.squeak.codeformatter import CodeFormatter, Message from pypy.translator.squeak.codeformatter import Field, Assignment, CustomVariable -from pypy.rpython.ootypesystem.ootype import Instance, Class, ROOT +from pypy.rpython.ootypesystem.ootype import Instance, Class, ROOT, _view class CodeNode: @@ -341,10 +341,17 @@ def dependencies(self): # Important: Field initializers for the *runtime* type - return [FieldInitializerNode(self.gen, c.value._TYPE) + return [FieldInitializerNode(self.gen, self._dynamic_type(c.value)) for c in self.constants.iterkeys()] + \ [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] + def _dynamic_type(self, instance): + # XXX move this to ootype? + if isinstance(instance, _view): + return instance._inst._TYPE + else: + return instance._TYPE + def render(self): codef = CodeFormatter(self.gen) # XXX use CodeFormatter throughout here @@ -354,9 +361,10 @@ yield codef.format(message.with_args([])) yield " Constants := Dictionary new." for const, const_id in self.constants.iteritems(): - INST = const.value._TYPE + INST = self._dynamic_type(const.value) + inst = const.value._downcast(INST) field_names = INST._allfields().keys() - field_values = [getattr(const.value, f) for f in field_names] + field_values = [getattr(inst, f) for f in field_names] new = Message("new").send_to(INST, []) init_message = Message("fieldInit").send_to(new, field_values) yield " Constants at: '%s' put: %s." \ From nik at codespeak.net Tue Mar 21 13:55:53 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 21 Mar 2006 13:55:53 +0100 (CET) Subject: [pypy-svn] r24675 - in pypy/dist/pypy/rpython/ootypesystem: . test Message-ID: <20060321125553.F27B110114@code0.codespeak.net> Author: nik Date: Tue Mar 21 13:55:51 2006 New Revision: 24675 Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py Log: (nik, input from pedronis) add dynamicType helper to ootypesystem. Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Tue Mar 21 13:55:51 2006 @@ -427,6 +427,10 @@ assert isinstance(typeOf(inst), Instance) return inst._classof() +def dynamicType(inst): + assert isinstance(typeOf(inst), Instance) + return classof(inst)._INSTANCE + def subclassof(class1, class2): assert isinstance(class1, _class) assert isinstance(class2, _class) Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py Tue Mar 21 13:55:51 2006 @@ -55,6 +55,17 @@ assert classof(i2) is not classof(i) assert classof(i2) != classof(i) +def test_dynamictype(): + A = Instance("A", ROOT) + B = Instance("B", A) + a = new(A) + b = new(B) + assert dynamicType(a) is A + assert dynamicType(b) is B + + b = ooupcast(A, b) + assert dynamicType(b) is B + def test_simple_default_class(): I = Instance("test", ROOT, {"a": (Signed, 3)}) i = new(I) From nik at codespeak.net Tue Mar 21 14:06:43 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 21 Mar 2006 14:06:43 +0100 (CET) Subject: [pypy-svn] r24676 - in pypy/dist/pypy: rpython/ootypesystem/test rpython/test translator/squeak Message-ID: <20060321130643.C99831010A@code0.codespeak.net> Author: nik Date: Tue Mar 21 14:06:42 2006 New Revision: 24676 Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py pypy/dist/pypy/rpython/test/test_rpbc.py pypy/dist/pypy/translator/squeak/node.py Log: use dynamicType where appropriate or necessary. Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/test/test_oopbc.py Tue Mar 21 14:06:42 2006 @@ -28,9 +28,9 @@ cls = A return cls() res = interpret(f, [0], type_system='ootype') - assert ootype.classof(res)._INSTANCE._name.split(".")[-1] == 'A' + assert ootype.dynamicType(res)._name.split(".")[-1] == 'A' res = interpret(f, [1], type_system='ootype') - assert ootype.classof(res)._INSTANCE._name.split(".")[-1] == 'B' + assert ootype.dynamicType(res)._name.split(".")[-1] == 'B' def test_call_classes_init(): class A: Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Tue Mar 21 14:06:42 2006 @@ -1388,9 +1388,9 @@ ts = "ootype" def class_name(self, value): - return ootype.classof(value)._INSTANCE._name.split(".")[-1] + return ootype.dynamicType(value)._name.split(".")[-1] def read_attr(self, value, attr): - value = ootype.oodowncast(ootype.classof(value)._INSTANCE, value) + value = ootype.oodowncast(ootype.dynamicType(value), value) return getattr(value, "o" + attr) Modified: pypy/dist/pypy/translator/squeak/node.py ============================================================================== --- pypy/dist/pypy/translator/squeak/node.py (original) +++ pypy/dist/pypy/translator/squeak/node.py Tue Mar 21 14:06:42 2006 @@ -4,6 +4,7 @@ from pypy.translator.squeak.codeformatter import CodeFormatter, Message from pypy.translator.squeak.codeformatter import Field, Assignment, CustomVariable from pypy.rpython.ootypesystem.ootype import Instance, Class, ROOT, _view +from pypy.rpython.ootypesystem.ootype import dynamicType, oodowncast class CodeNode: @@ -159,7 +160,7 @@ exc_exits.append(exit) for exit in exc_exits: yield "(%s type isKindOf: %s) ifTrue: [" \ - % (exc_var, codef.format(exit.llexitcase)) + % (exc_var, codef.format(dynamicType(exit.llexitcase))) if exit.last_exception is not None: yield "%s := %s type." \ % (codef.format(exit.last_exception), exc_var) @@ -341,17 +342,10 @@ def dependencies(self): # Important: Field initializers for the *runtime* type - return [FieldInitializerNode(self.gen, self._dynamic_type(c.value)) + return [FieldInitializerNode(self.gen, dynamicType(c.value)) for c in self.constants.iterkeys()] + \ [ClassNode(self.gen, self.CONSTANTS, class_vars=["Constants"])] - def _dynamic_type(self, instance): - # XXX move this to ootype? - if isinstance(instance, _view): - return instance._inst._TYPE - else: - return instance._TYPE - def render(self): codef = CodeFormatter(self.gen) # XXX use CodeFormatter throughout here @@ -361,8 +355,8 @@ yield codef.format(message.with_args([])) yield " Constants := Dictionary new." for const, const_id in self.constants.iteritems(): - INST = self._dynamic_type(const.value) - inst = const.value._downcast(INST) + INST = dynamicType(const.value) + inst = oodowncast(INST, const.value) field_names = INST._allfields().keys() field_values = [getattr(inst, f) for f in field_names] new = Message("new").send_to(INST, []) From auc at codespeak.net Tue Mar 21 14:52:14 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 21 Mar 2006 14:52:14 +0100 (CET) Subject: [pypy-svn] r24677 - pypy/dist/pypy/objspace/test Message-ID: <20060321135214.8EF76100FE@code0.codespeak.net> Author: auc Date: Tue Mar 21 14:52:03 2006 New Revision: 24677 Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: updated tests Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Tue Mar 21 14:52:03 2006 @@ -5,7 +5,7 @@ def setup_class(cls): cls.space = gettestobjspace('logic') - def test_simple(self): + def test_simple_bind(self): X = newvar() assert is_free(X) bind(X, 1) @@ -14,7 +14,7 @@ assert is_bound(1) raises(TypeError, bind, 1, 2) - def test_setitem(self): + def test_setitem_bind(self): x = newvar() d = {5: x} d[6] = x @@ -27,7 +27,14 @@ for x in [d[5], d[6], d[7][0]]: assert is_bound(d[5]) - def test_unbound_unification_simple(self): + def test_bind_to_self(self): + X = newvar() + assert is_free(X) + bind(X, X) + bind(X, 1) + assert X == 1 + + def test_bind_aliased(self): X = newvar() Y = newvar() bind(X, Y) @@ -49,32 +56,32 @@ return x + 1 raises(RuntimeError, f, X) - def test_bind_to_self(self): - X = newvar() - bind(X, X) - bind(X, 1) - assert X == 1 def test_eq_unifies_simple(self): X = newvar() Y = newvar() - assert X == Y + unify(X, Y) + unify(X, 1) assert X == 1 assert is_bound(Y) assert Y == 1 + assert X == Y - def test_ne_of_unified_vars(self): + def test_ne_of_unified_unbound_vars(self): X = newvar() Y = newvar() + unify(X, Y) assert X == Y assert not X != Y def test_cmp(self): X = newvar() Y = newvar() + unify(X, Y) assert cmp(X, Y) == 0 assert is_free(X) assert is_free(Y) + unify(X, 1) assert X == 1 assert is_bound(Y) assert Y == 1 @@ -82,7 +89,82 @@ def test_is(self): X = newvar() x = 1 - assert X is x + assert 1 is 1 + assert not(2 is 1) + assert X is X + bind(X, x) assert X == 1 assert X is x + assert not(X is 2) + + def test_unify_free(self): + X, Y = newvar(), newvar() + unify(X, Y) + assert X == Y + unify(X, 1) + assert X == 1 + assert Y == 1 + + + +class AppTest_LogicThreads(object): + + def setup_class(cls): + cls.space = gettestobjspace('logic') + + + def notest_eager_producer_consummer(self): + + def generate(n, limit): + print "generate", n, limit + if n < limit: + return (n, generate(n + 1, limit)) + return (None, None) + + def sum(L, a): + print "sum", a + head, Tail = newvar(), newvar() + unify(L, (head, Tail)) + if head != None: + return sum(Tail, head + a) + return a + + X = newvar() + S = newvar() + unify(S, uthread(sum, X, 0)) + unify(X, uthread(generate, 0, 10)) + + assert S == 45 + + + def notest_lazy_producer_consummer(self): + + def lgenerate(n, L): + """wait-needed version of generate""" + print "generator waits on L being needed" + wait_needed(L) + Tail = newvar() + L == (n, Tail) + print "generator bound L to", L + lgenerate(n+1, Tail) + + def lsum(L, a, limit): + """this version of sum controls the generator""" + print "sum", a + if limit > 0: + Head, Tail = newvar(), newvar() + print "sum waiting on L" + L == (Head, Tail) # or Head, Tail == L ? + return lsum(Tail, a+Head, limit-1) + else: + return a + + print "lazy producer consummer" + print "before" + Y = newvar() + T = newvar() + uthread(lgenerate, 0, Y) + T == uthread(lsum, Y, 0, 10) + print "after" + print T From ac at codespeak.net Tue Mar 21 14:58:48 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 21 Mar 2006 14:58:48 +0100 (CET) Subject: [pypy-svn] r24678 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060321135848.31B9210101@code0.codespeak.net> Author: ac Date: Tue Mar 21 14:58:42 2006 New Revision: 24678 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: Update Strakt data. Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Tue Mar 21 14:58:42 2006 @@ -11,13 +11,14 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== -Anders Chrigstroem 2/3 - 10/3 Ermina +Anders Chrigstroem 30/3 - 10/4 Ermina Holger Krekel 1st - 14 Ermina -Samuele Pedroni 2/3 - 10/3 Ermina +Samuele Pedroni 30/3 - 10/4 Ermina Armin Rigo -- private Christian Tismer ? Ermina? Michael Hudson 3rd-10th? Ermina? Anders Lehmann 2nd-9th Ermina +Jacob Hallen 30/3 - 7/4 Ermina ==================== ============== ===================== People on the following list were present at previous sprints: @@ -33,7 +34,6 @@ Bert Freudenberg ? ? Ludovic Aubry ? ? Adrien Di Mascio ? ? -Jacob Hallen ? ? Laura Creighton ? ? Beatrice Duering ? ? Eric van Riet Paap ? ? From nik at codespeak.net Tue Mar 21 15:17:33 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Tue, 21 Mar 2006 15:17:33 +0100 (CET) Subject: [pypy-svn] r24684 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060321141733.00DD01010C@code0.codespeak.net> Author: nik Date: Tue Mar 21 15:17:32 2006 New Revision: 24684 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: my leysin dates Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Tue Mar 21 15:17:32 2006 @@ -19,6 +19,7 @@ Michael Hudson 3rd-10th? Ermina? Anders Lehmann 2nd-9th Ermina Jacob Hallen 30/3 - 7/4 Ermina +Niklaus Haldimann 2/4 - 5/4 Ermina ==================== ============== ===================== People on the following list were present at previous sprints: @@ -38,7 +39,6 @@ Beatrice Duering ? ? Eric van Riet Paap ? ? Carl Friedrich Bolz ? ? -Niklaus Haldimann ? ? Richard Emslie ? ? Johan Hahn ? ? ==================== ============== ===================== From mwh at codespeak.net Tue Mar 21 15:26:51 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 21 Mar 2006 15:26:51 +0100 (CET) Subject: [pypy-svn] r24686 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060321142651.B5950100F6@code0.codespeak.net> Author: mwh Date: Tue Mar 21 15:26:50 2006 New Revision: 24686 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: i've booked flights now, and am arriving on the 2nd (just :) Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Tue Mar 21 15:26:50 2006 @@ -16,7 +16,7 @@ Samuele Pedroni 30/3 - 10/4 Ermina Armin Rigo -- private Christian Tismer ? Ermina? -Michael Hudson 3rd-10th? Ermina? +Michael Hudson 2nd-10th Ermina Anders Lehmann 2nd-9th Ermina Jacob Hallen 30/3 - 7/4 Ermina Niklaus Haldimann 2/4 - 5/4 Ermina From pedronis at codespeak.net Tue Mar 21 17:26:01 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 17:26:01 +0100 (CET) Subject: [pypy-svn] r24696 - in pypy/dist/pypy/jit: . test Message-ID: <20060321162601.7974C10112@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 17:25:58 2006 New Revision: 24696 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_annotation.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: (arre, pedronis) pass one more test of the ones in progress. renamed some tests for clarity. The code in hintrtyper is reaching a point where extracting some helpers may help readability. Now is getting to a sort blob. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Tue Mar 21 17:25:58 2006 @@ -146,10 +146,49 @@ if isinstance(hop.args_r[0], BlueRepr): return hop.args_r[0].timeshift_setfield(hop) # non virtual case ... - raise NotImplementedError + ts = self.timeshifter + PTRTYPE = originalconcretetype(hop.args_s[0]) + VALUETYPE = originalconcretetype(hop.args_s[2]) + v_destbox, c_fieldname, v_valuebox = hop.inputargs(self.getredrepr(PTRTYPE), + green_void_repr, + self.getredrepr(VALUETYPE) + ) + fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) + c_fielddesc = inputconst(lltype.Void, fielddesc) + s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) + gv_fieldname = rgenop.constFieldName(c_fieldname.value) + c_fieldname = hop.inputconst(rgenop.CONSTORVAR, gv_fieldname) + v_jitstate = hop.llops.getjitstate() + s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_setfield, + [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR, ts.s_RedBox], + [v_jitstate, c_fielddesc, v_destbox, c_fieldname, v_valuebox], + annmodel.s_None) def translate_op_getsubstruct(self, hop): - return hop.args_r[0].timeshift_getsubstruct(hop) + if isinstance(hop.args_r[0], BlueRepr): + return hop.args_r[0].timeshift_getsubstruct(hop) + # non virtual case + # XXX green getfields on an immutable structure could be more efficient + ts = self.timeshifter + PTRTYPE = originalconcretetype(hop.args_s[0]) + RESTYPE = originalconcretetype(hop.s_result) + v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), + green_void_repr) + fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) + c_fielddesc = inputconst(lltype.Void, fielddesc) + s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) + gv_fieldname = rgenop.constFieldName(c_fieldname.value) + gv_resulttype = rgenop.constTYPE(RESTYPE) + c_fieldname = hop.inputconst(rgenop.CONSTORVAR, gv_fieldname) + c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) + v_jitstate = hop.llops.getjitstate() + s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getsubstruct, + [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR, s_CONSTORVAR], + [v_jitstate, c_fielddesc, v_argbox, c_fieldname, c_resulttype], + ts.s_RedBox) + def translate_op_malloc(self, hop): r_result = hop.r_result @@ -277,7 +316,19 @@ return [ll_value] def create(self, hop): - XXX #... + ts = self.timeshifter + s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) + RESTYPE = self.original_concretetype + gv_type = rgenop.constTYPE(RESTYPE.TO) + c_type = hop.inputconst(rgenop.CONSTORVAR, gv_type) + gv_resulttype = rgenop.constTYPE(RESTYPE) + c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) + v_jitstate = hop.llops.getjitstate() + + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_malloc, + [ts.s_JITState, s_CONSTORVAR, s_CONSTORVAR], + [v_jitstate, c_type, c_resulttype], + ts.s_RedBox) class BlueRepr(Repr): Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Tue Mar 21 17:25:58 2006 @@ -234,6 +234,31 @@ gv_resulttype) return VarRedBox(genvar) +gv_Void = rgenop.constTYPE(lltype.Void) + +def ll_generate_setfield(jitstate, fielddesc, destbox, + gv_fieldname, valuebox): + op_args = lltype.malloc(VARLIST.TO, 3) + op_args[0] = destbox.getgenvar() + op_args[1] = gv_fieldname + op_args[2] = valuebox.getgenvar() + rgenop.genop(jitstate.curblock, 'setfield', op_args, + gv_Void) + + + +def ll_generate_getsubstruct(jitstate, fielddesc, argbox, + gv_fieldname, gv_resulttype): + if isinstance(argbox, ConstRedBox): + res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) + return ConstRedBox.ll_fromvalue(res) + op_args = lltype.malloc(VARLIST.TO, 2) + op_args[0] = argbox.getgenvar() + op_args[1] = gv_fieldname + genvar = rgenop.genop(jitstate.curblock, 'getsubstruct', op_args, + gv_resulttype) + return VarRedBox(genvar) + def ll_generate_getarrayitem(jitstate, fielddesc, argbox, indexbox, gv_resulttype): @@ -248,6 +273,12 @@ gv_resulttype) return VarRedBox(genvar) +def ll_generate_malloc(jitstate, gv_type, gv_resulttype): + op_args = lltype.malloc(VARLIST.TO, 1) + op_args[0] = gv_type + genvar = rgenop.genop(jitstate.curblock, 'malloc', op_args, + gv_resulttype) + return VarRedBox(genvar) # ____________________________________________________________ # other jitstate/graph level operations Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/dist/pypy/jit/test/test_hint_annotation.py Tue Mar 21 17:25:58 2006 @@ -306,7 +306,7 @@ hs = hannotate(ll1, [int]) assert isinstance(hs, SomeLLAbstractVariable) -def test_merge_substructure(): +def test_degenerated_merge_substructure(): S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Tue Mar 21 17:25:58 2006 @@ -320,8 +320,7 @@ assert res == 7 assert insns == {} -def test_merge_substructure(): - py.test.skip("in-progress") +def test_degenerated_merge_substructure(): S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) @@ -335,7 +334,7 @@ return s insns, res = timeshift(ll_function, [0], []) assert res.n == 4 - assert insns == {'malloc': 1, 'setfield': 1, 'getfield': 1} + assert insns == {'getsubstruct': 2, 'int_is_true': 1, 'malloc': 2, 'setfield': 2} def test_plus_minus_all_inlined(): py.test.skip("in-progress") From pedronis at codespeak.net Tue Mar 21 18:29:49 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 18:29:49 +0100 (CET) Subject: [pypy-svn] r24708 - in pypy/dist/pypy/jit: . test Message-ID: <20060321172949.4C98D10132@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 18:29:42 2006 New Revision: 24708 Modified: pypy/dist/pypy/jit/hintcontainer.py pypy/dist/pypy/jit/test/test_hint_annotation.py Log: (arre, pedronis) record the structural information about the parent index in virtual struct def annotations. extend union to consider. test for this behavior. Modified: pypy/dist/pypy/jit/hintcontainer.py ============================================================================== --- pypy/dist/pypy/jit/hintcontainer.py (original) +++ pypy/dist/pypy/jit/hintcontainer.py Tue Mar 21 18:29:42 2006 @@ -32,19 +32,19 @@ # ____________________________________________________________ -def virtualcontainerdef(bookkeeper, T, vparent=None): +def virtualcontainerdef(bookkeeper, T, vparent=None, vparentindex=0): """Build and return a VirtualXxxDef() corresponding to a freshly allocated virtual container. """ if isinstance(T, lltype.Struct): - return VirtualStructDef(bookkeeper, T, vparent) + return VirtualStructDef(bookkeeper, T, vparent, vparentindex) elif isinstance(T, lltype.Array): return VirtualArrayDef(bookkeeper, T) raise TypeError("unsupported container type %r" % (T,)) -def make_item_annotation(bookkeeper, TYPE, vparent=None): +def make_item_annotation(bookkeeper, TYPE, vparent=None, vparentindex=0): if isinstance(TYPE, lltype.ContainerType): - vdef = virtualcontainerdef(bookkeeper, TYPE, vparent=vparent) + vdef = virtualcontainerdef(bookkeeper, TYPE, vparent, vparentindex) return hintmodel.SomeLLAbstractContainer(vdef) elif isinstance(TYPE, lltype.Ptr): return annmodel.s_ImpossibleValue @@ -76,16 +76,17 @@ class VirtualStructDef(AbstractContainerDef): - def __init__(self, bookkeeper, TYPE, vparent=None): + def __init__(self, bookkeeper, TYPE, vparent=None, vparentindex=0): AbstractContainerDef.__init__(self, bookkeeper, TYPE) self.fields = {} self.names = TYPE._names - for name in self.names: + for index, name in enumerate(self.names): FIELD_TYPE = self.fieldtype(name) - hs = make_item_annotation(bookkeeper, FIELD_TYPE, vparent=self) + hs = make_item_annotation(bookkeeper, FIELD_TYPE, vparent=self, vparentindex=index) fv = self.fields[name] = FieldValue(bookkeeper, name, hs) fv.itemof[self] = True self.vparent = vparent + self.vparentindex = vparentindex def cast(self, TO): down_or_up = lltype.castable(TO, @@ -119,7 +120,7 @@ incompatible = False if self.vparent is not None: if other.vparent is not None: - if self.vparent.T != other.vparent.T: + if self.vparent.T != other.vparent.T or self.vparentindex != other.vparentindex: incompatible = True else: self.vparent.union(other.vparent) Modified: pypy/dist/pypy/jit/test/test_hint_annotation.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_annotation.py (original) +++ pypy/dist/pypy/jit/test/test_hint_annotation.py Tue Mar 21 18:29:42 2006 @@ -329,6 +329,33 @@ assert isinstance(hs1, SomeLLAbstractContainer) assert hs1.contentdef.degenerated +def test_degenerated_merge_cross_substructure(): + from pypy.rpython import objectmodel + S = lltype.Struct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('s1', S), ('n', lltype.Float)) + + def ll_function(flag): + t = lltype.malloc(T) + t.s.n = 3 + t.s1.n = 3 + if flag: + s = t.s + else: + s = t.s1 + objectmodel.keepalive_until_here(t) + return s, t + hs = hannotate(ll_function, [bool]) + assert isinstance(hs, SomeLLAbstractContainer) + assert not hs.contentdef.degenerated + assert len(hs.contentdef.fields) == 2 + hs0 = hs.contentdef.fields['item0'].s_value # 's' + assert isinstance(hs0, SomeLLAbstractContainer) + assert hs0.contentdef.degenerated + hs1 = hs.contentdef.fields['item1'].s_value # 't' + assert isinstance(hs1, SomeLLAbstractContainer) + assert hs1.contentdef.degenerated + + def test_simple_fixed_call(): def ll_help(cond, x, y): if cond: From auc at codespeak.net Tue Mar 21 18:31:48 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 21 Mar 2006 18:31:48 +0100 (CET) Subject: [pypy-svn] r24709 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060321173148.AB71D10132@code0.codespeak.net> Author: auc Date: Tue Mar 21 18:31:41 2006 New Revision: 24709 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: logilab people Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Tue Mar 21 18:31:41 2006 @@ -20,6 +20,8 @@ Anders Lehmann 2nd-9th Ermina Jacob Hallen 30/3 - 7/4 Ermina Niklaus Haldimann 2/4 - 5/4 Ermina +Aurelien Campeas 3/4 - 7/4 Ermina +Alexandre Fayolle 3/4 - 7/4 Ermina ==================== ============== ===================== People on the following list were present at previous sprints: @@ -33,8 +35,6 @@ Boris Feigin ? ? Andrew Thompson ? ? Bert Freudenberg ? ? -Ludovic Aubry ? ? -Adrien Di Mascio ? ? Laura Creighton ? ? Beatrice Duering ? ? Eric van Riet Paap ? ? From pedronis at codespeak.net Tue Mar 21 18:41:50 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 18:41:50 +0100 (CET) Subject: [pypy-svn] r24711 - pypy/dist/pypy/jit Message-ID: <20060321174150.D7695100B0@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 18:41:39 2006 New Revision: 24711 Modified: pypy/dist/pypy/jit/hintcontainer.py Log: (arre, pedronis) half-hearted attempt at using vparent of array items too. This makes really sense only if dealt with the fixed size case only. Modified: pypy/dist/pypy/jit/hintcontainer.py ============================================================================== --- pypy/dist/pypy/jit/hintcontainer.py (original) +++ pypy/dist/pypy/jit/hintcontainer.py Tue Mar 21 18:41:39 2006 @@ -39,7 +39,7 @@ if isinstance(T, lltype.Struct): return VirtualStructDef(bookkeeper, T, vparent, vparentindex) elif isinstance(T, lltype.Array): - return VirtualArrayDef(bookkeeper, T) + return VirtualArrayDef(bookkeeper, T, vparent) raise TypeError("unsupported container type %r" % (T,)) def make_item_annotation(bookkeeper, TYPE, vparent=None, vparentindex=0): @@ -154,14 +154,15 @@ for varraydef in self.itemof: varraydef.arrayitem = self - +# this may need to really be used only for fixed size cases class VirtualArrayDef(AbstractContainerDef): - def __init__(self, bookkeeper, TYPE): + def __init__(self, bookkeeper, TYPE, vparent=None): AbstractContainerDef.__init__(self, bookkeeper, TYPE) - hs = make_item_annotation(bookkeeper, TYPE.OF) + hs = make_item_annotation(bookkeeper, TYPE.OF, vparent=self) # xxx vparentindex? self.arrayitem = ArrayItem(bookkeeper, hs) self.arrayitem.itemof[self] = True + self.vparent = vparent def read_item(self): self.arrayitem.read_locations[self.bookkeeper.position_key] = True From pedronis at codespeak.net Tue Mar 21 18:55:47 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 18:55:47 +0100 (CET) Subject: [pypy-svn] r24713 - pypy/dist/pypy/jit Message-ID: <20060321175547.1FF2A100B0@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 18:55:45 2006 New Revision: 24713 Modified: pypy/dist/pypy/jit/hintrtyper.py Log: (arre, pedronis) substitute the hackish and wrong code in blue structs makekey, with at least reasonably looking code, although what is really needed will depend on how exactly we will use the information. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Tue Mar 21 18:55:45 2006 @@ -264,21 +264,11 @@ # fall back to a red repr return hs_container.__class__, "red", hs_container.concretetype - # compute reconstruction information up to our top-most parent - chain = [vstructdef.T] - cur = vstructdef - while cur.vparent is not None: - for name, fieldvalue in cur.vparent.fields.iteritems(): - s_field = fieldvalue.s_value - if isinstance(s_field, hintmodel.SomeLLAbstractContainer): - if s_field.contentdef is cur: - chain.append((name, cur.vparent.T)) - break - else: - assert False, "can't find ourself in parent" - cur = cur.vparent + T = None + if vstructdef.vparent is not None: + T = vstructdef.vparent.T - key = [hs_container.__class__, tuple(chain)] + key = [hs_container.__class__, vstructdef.T, T, vstructdef.vparentindex] for name in vstructdef.names: fielditem = vstructdef.fields[name] key.append(fielditem) From pedronis at codespeak.net Tue Mar 21 20:28:21 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 20:28:21 +0100 (CET) Subject: [pypy-svn] r24720 - pypy/dist/pypy/rpython Message-ID: <20060321192821.101901011E@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 20:28:11 2006 New Revision: 24720 Modified: pypy/dist/pypy/rpython/raddress.py Log: conversion from Ptr to Address. equality and hash (bad) functions for addresses. Need a new op for addr->int (later). Modified: pypy/dist/pypy/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/dist/pypy/rpython/raddress.py Tue Mar 21 20:28:11 2006 @@ -4,6 +4,7 @@ from pypy.rpython.memory.lladdress import NULL, address from pypy.rpython.lltypesystem.llmemory import Address from pypy.rpython.rmodel import Repr, IntegerRepr +from pypy.rpython.rptr import PtrRepr from pypy.rpython.lltypesystem import lltype class __extend__(annmodel.SomeAddress): @@ -37,6 +38,16 @@ return hop.genop('adr_ne', [v_addr, c_null], resulttype=lltype.Bool) + def get_ll_eq_function(self): + def ll_eq(addr1, addr2): + return addr1 == addr2 + return ll_eq + + def get_ll_hash_function(self): + def ll_hash(addr1): + return 0 # XXX do better + return ll_hash + address_repr = AddressRepr() @@ -111,3 +122,9 @@ v_addr1, v_addr2 = hop.inputargs(Address, Address) return hop.genop('adr_ge', [v_addr1, v_addr2], resulttype=lltype.Bool) +# conversions + +class __extend__(pairtype(PtrRepr, AddressRepr)): + + def convert_from_to((r_ptr, r_addr), v, llops): + return llops.genop('cast_ptr_to_adr', [v], resulttype=Address) From pedronis at codespeak.net Tue Mar 21 20:29:55 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 20:29:55 +0100 (CET) Subject: [pypy-svn] r24721 - in pypy/dist/pypy/jit: . test Message-ID: <20060321192955.2D40D10138@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 20:29:48 2006 New Revision: 24721 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/hinttimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: pass test_plus_minus_all_inlined there was a bug about green key values being carried around in their erased form instead of simply the original one. Fold getfield/arrayitem if the arguments are green and the container immutable. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Tue Mar 21 20:29:48 2006 @@ -59,9 +59,9 @@ self.red_reprs[lowleveltype] = r return r - def generic_translate_operation(self, hop): + def generic_translate_operation(self, hop, force=False): # detect constant-foldable all-green operations - if hop.spaceop.opname not in rtimeshift.FOLDABLE_OPS: + if not force and hop.spaceop.opname not in rtimeshift.FOLDABLE_OPS: return None green = True for r_arg in hop.args_r: @@ -99,13 +99,20 @@ # don't try to generate hint operations, just discard them return hop.inputarg(hop.r_result, arg=0) + def translate_op_keepalive(self,hop): + pass + def translate_op_getfield(self, hop): if isinstance(hop.args_r[0], BlueRepr): return hop.args_r[0].timeshift_getfield(hop) # non virtual case - # XXX green getfields on an immutable structure could be more efficient - ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) + if PTRTYPE.TO._hints.get('immutable', False): # foldable if all green + res = self.generic_translate_operation(hop, force=True) + if res is not None: + return res + + ts = self.timeshifter RESTYPE = originalconcretetype(hop.s_result) v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), green_void_repr) @@ -124,9 +131,13 @@ ts.s_RedBox) def translate_op_getarrayitem(self, hop): - # XXX green getarrayitems on an immutable array could be more efficient - ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) + if PTRTYPE.TO._hints.get('immutable', False): # foldable if all green + res = self.generic_translate_operation(hop, force=True) + if res is not None: + return res + + ts = self.timeshifter RESTYPE = originalconcretetype(hop.s_result) v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), self.getredrepr(lltype.Signed)) @@ -169,7 +180,6 @@ if isinstance(hop.args_r[0], BlueRepr): return hop.args_r[0].timeshift_getsubstruct(hop) # non virtual case - # XXX green getfields on an immutable structure could be more efficient ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) RESTYPE = originalconcretetype(hop.s_result) Modified: pypy/dist/pypy/jit/hinttimeshift.py ============================================================================== --- pypy/dist/pypy/jit/hinttimeshift.py (original) +++ pypy/dist/pypy/jit/hinttimeshift.py Tue Mar 21 20:29:48 2006 @@ -295,6 +295,7 @@ getrepr = self.rtyper.getrepr items_s = [] key_v = [] + orig_key_v = [] for r, newvar in zip(args_r, newinputargs): if isinstance(r, GreenRepr): r_from = getrepr(r.annotation()) @@ -302,6 +303,7 @@ r_to = getrepr(erased_s) items_s.append(erased_s) erased_v = llops.convertvar(newvar, r_from, r_to) + orig_key_v.append(newvar) key_v.append(erased_v) s_key_tuple = annmodel.SomeTuple(items_s) @@ -331,13 +333,13 @@ read_boxes_block_vars = [v_newjitstate2, v_boxes2] - for greenvar in key_v: + for greenvar in orig_key_v: greenvar2 = flowmodel.Variable(greenvar) greenvar2.concretetype = greenvar.concretetype read_boxes_block_vars.append(greenvar2) read_boxes_block = flowmodel.Block(read_boxes_block_vars) - to_read_boxes_block = flowmodel.Link([v_newjitstate, v_boxes] + key_v, read_boxes_block) + to_read_boxes_block = flowmodel.Link([v_newjitstate, v_boxes] + orig_key_v, read_boxes_block) to_read_boxes_block.exitcase = to_read_boxes_block.llexitcase = True to_dispatch_block = flowmodel.Link([v_oldjitstate], self.dispatchblock) to_dispatch_block.exitcase = to_dispatch_block.llexitcase = False Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Tue Mar 21 20:29:48 2006 @@ -337,7 +337,6 @@ assert insns == {'getsubstruct': 2, 'int_is_true': 1, 'malloc': 2, 'setfield': 2} def test_plus_minus_all_inlined(): - py.test.skip("in-progress") def ll_plus_minus(s, x, y): acc = x n = len(s) @@ -353,5 +352,5 @@ return acc s = rstr.string_repr.convert_const("+-+") insns, res = timeshift(ll_plus_minus, [s, 0, 2], [0], inline=999) - assert res == ll_plus_minus(s, 0, 2) + assert res == ll_plus_minus("+-+", 0, 2) assert insns == {'int_add': 2, 'int_sub': 1} From pedronis at codespeak.net Tue Mar 21 22:23:47 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 22:23:47 +0100 (CET) Subject: [pypy-svn] r24732 - pypy/dist/pypy/rpython/memory Message-ID: <20060321212347.EEC9410137@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 22:23:46 2006 New Revision: 24732 Modified: pypy/dist/pypy/rpython/memory/gctransform.py Log: 8mb default start heap size for MS. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Tue Mar 21 22:23:46 2006 @@ -716,7 +716,7 @@ super(FrameworkGCTransformer, self).__init__(translator, inline=True) class GCData(object): from pypy.rpython.memory.gc import MarkSweepGC as GCClass - startheapsize = 640*1024 # XXX adjust + startheapsize = 8*1024*1024 # XXX adjust rootstacksize = 640*1024 # XXX adjust # types of the GC information tables From pedronis at codespeak.net Tue Mar 21 22:25:07 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Mar 2006 22:25:07 +0100 (CET) Subject: [pypy-svn] r24733 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory Message-ID: <20060321212507.8653F10137@code0.codespeak.net> Author: pedronis Date: Tue Mar 21 22:24:58 2006 New Revision: 24733 Modified: pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/llmemory.py pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py pypy/dist/pypy/rpython/memory/lladdress.py pypy/dist/pypy/rpython/raddress.py pypy/dist/pypy/rpython/rbuiltin.py Log: cast_adr_to_int. proper hashing for addresses. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Tue Mar 21 22:24:58 2006 @@ -322,6 +322,9 @@ assert s_type.is_constant() return SomePtr(s_type.const) +def llmemory_cast_adr_to_int(s): + return SomeInteger() # xxx + def rstack_yield_current_frame_to_caller(): return SomeExternalObject(pypy.rpython.rstack.frame_stack_top) @@ -369,6 +372,7 @@ BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hint] = robjmodel_hint BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_ptr_to_adr] = llmemory_cast_ptr_to_adr BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_ptr] = llmemory_cast_adr_to_ptr +BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_int] = llmemory_cast_adr_to_int BUILTIN_ANALYZERS[pypy.rpython.rstack.yield_current_frame_to_caller] = ( rstack_yield_current_frame_to_caller) Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Tue Mar 21 22:24:58 2006 @@ -511,6 +511,10 @@ assert checkadr(adr) return llmemory.cast_adr_to_ptr(adr, TYPE) + def op_cast_adr_to_int(self, adr): + assert checkadr(adr) + return llmemory.cast_adr_to_int(adr) + def op_cast_int_to_float(self, i): assert type(i) is int return float(i) Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/llmemory.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py Tue Mar 21 22:24:58 2006 @@ -154,6 +154,9 @@ def _cast_to_ptr(self, EXPECTED_TYPE): return lltype.cast_pointer(EXPECTED_TYPE, self.get()) + def _cast_to_int(self): + return self.get()._cast_to_int() + # XXX the indexing in code like # addr.signed[0] = v # is just silly. remove it. @@ -202,3 +205,6 @@ def cast_adr_to_ptr(adr, EXPECTED_TYPE): return adr._cast_to_ptr(EXPECTED_TYPE) +def cast_adr_to_int(adr): + return adr._cast_to_int() + Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Tue Mar 21 22:24:58 2006 @@ -267,6 +267,7 @@ 'adr_ge': LLOp(canfold=True), 'cast_ptr_to_adr': LLOp(canfold=True), 'cast_adr_to_ptr': LLOp(canfold=True), + 'cast_adr_to_int': LLOp(canfold=True), # __________ GC operations __________ Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py Tue Mar 21 22:24:58 2006 @@ -80,3 +80,18 @@ return s1 == s2 res = interpret(f, []) assert res + +def test_cast_adr_to_int(): + from pypy.rpython.memory.test.test_llinterpsim import interpret + from pypy.rpython.lltypesystem import lltype + S = lltype.GcStruct("S", ("x", lltype.Signed)) + Sptr = lltype.Ptr(S) + def f(): + s1 = lltype.malloc(S) + adr = cast_ptr_to_adr(s1) + i = cast_adr_to_int(adr) + i2 = lltype.cast_ptr_to_int(s1) + return i == i2 + assert f() + res = interpret(f, []) + assert res Modified: pypy/dist/pypy/rpython/memory/lladdress.py ============================================================================== --- pypy/dist/pypy/rpython/memory/lladdress.py (original) +++ pypy/dist/pypy/rpython/memory/lladdress.py Tue Mar 21 22:24:58 2006 @@ -62,6 +62,9 @@ def _cast_to_ptr(self, EXPECTED_TYPE): from pypy.rpython.memory.lltypesimulation import simulatorptr return simulatorptr(EXPECTED_TYPE, self) + + def _cast_to_int(self): + return self.intaddress class _accessor(object): Modified: pypy/dist/pypy/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/dist/pypy/rpython/raddress.py Tue Mar 21 22:24:58 2006 @@ -2,7 +2,7 @@ from pypy.annotation.pairtype import pairtype from pypy.annotation import model as annmodel from pypy.rpython.memory.lladdress import NULL, address -from pypy.rpython.lltypesystem.llmemory import Address +from pypy.rpython.lltypesystem.llmemory import Address, cast_adr_to_int from pypy.rpython.rmodel import Repr, IntegerRepr from pypy.rpython.rptr import PtrRepr from pypy.rpython.lltypesystem import lltype @@ -45,7 +45,7 @@ def get_ll_hash_function(self): def ll_hash(addr1): - return 0 # XXX do better + return cast_adr_to_int(addr1) return ll_hash Modified: pypy/dist/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/rbuiltin.py Tue Mar 21 22:24:58 2006 @@ -485,6 +485,14 @@ return hop.genop('cast_adr_to_ptr', [adr], resulttype = TYPE.value) +def rtype_cast_adr_to_int(hop): + assert isinstance(hop.args_r[0], raddress.AddressRepr) + adr, = hop.inputargs(hop.args_r[0]) + hop.exception_cannot_occur() + return hop.genop('cast_adr_to_int', [adr], + resulttype = lltype.Signed) + BUILTIN_TYPER[llmemory.cast_ptr_to_adr] = rtype_cast_ptr_to_adr BUILTIN_TYPER[llmemory.cast_adr_to_ptr] = rtype_cast_adr_to_ptr +BUILTIN_TYPER[llmemory.cast_adr_to_int] = rtype_cast_adr_to_int From tismer at codespeak.net Wed Mar 22 00:56:18 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 22 Mar 2006 00:56:18 +0100 (CET) Subject: [pypy-svn] r24757 - pypy/dist/pypy/translator/c Message-ID: <20060321235618.7D2E1100EA@code0.codespeak.net> Author: tismer Date: Wed Mar 22 00:56:10 2006 New Revision: 24757 Modified: pypy/dist/pypy/translator/c/wrapper.py Log: make the generated wrapper function(s) also visible in the final graph Modified: pypy/dist/pypy/translator/c/wrapper.py ============================================================================== --- pypy/dist/pypy/translator/c/wrapper.py (original) +++ pypy/dist/pypy/translator/c/wrapper.py Wed Mar 22 00:56:10 2006 @@ -119,6 +119,8 @@ # "return result" block = Block([vself, vargs, vkwds]) wgraph = FunctionGraph('pyfn_' + func.func_name, block) + translator.update_call_graph(wgraph, graph, object()) + translator.graphs.append(wgraph) block.operations[:] = newops block.closeblock(Link([vresult], wgraph.returnblock)) checkgraph(wgraph) From tismer at codespeak.net Wed Mar 22 04:04:11 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 22 Mar 2006 04:04:11 +0100 (CET) Subject: [pypy-svn] r24768 - pypy/dist/pypy/translator/c/winproj/extension Message-ID: <20060322030411.69061100C3@code0.codespeak.net> Author: tismer Date: Wed Mar 22 04:03:56 2006 New Revision: 24768 Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Log: tiny changes for easier testing Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Wed Mar 22 04:03:56 2006 @@ -34,7 +34,7 @@ + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-829\testing_1\common_header.h"> + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-829\testing_1\testing_1.c"> From tismer at codespeak.net Wed Mar 22 04:05:44 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 22 Mar 2006 04:05:44 +0100 (CET) Subject: [pypy-svn] r24769 - pypy/dist/pypy/translator/c Message-ID: <20060322030544.3A19F100C3@code0.codespeak.net> Author: tismer Date: Wed Mar 22 04:05:36 2006 New Revision: 24769 Modified: pypy/dist/pypy/translator/c/funcgen.py Log: there are ugly refcounting bugs with PyObjects. Could not yet clean this up. See email Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Wed Mar 22 04:05:36 2006 @@ -11,6 +11,9 @@ PyObjPtr = Ptr(PyObject) LOCALVAR = 'l_%s' +# I'm not absolutely sure, so just in case: +NEED_OLD_EXTRA_REFS = True # oupps seems to be + class FunctionCodeGenerator(object): """ Collects information about a function which we have to generate @@ -455,7 +458,7 @@ newvalue = self.expr(op.result, special_case_void=False) result = ['%s = %s;' % (newvalue, sourceexpr)] # need to adjust the refcount of the result only for PyObjects - if T == PyObjPtr: + if NEED_OLD_EXTRA_REFS and T == PyObjPtr: result.append('Py_XINCREF(%s);' % newvalue) result = '\n'.join(result) if T is Void: @@ -599,7 +602,7 @@ cdecl(typename, ''), self.expr(op.args[0]))) - if TYPE == PyObjPtr: + if NEED_OLD_EXTRA_REFS and TYPE == PyObjPtr: result.append('Py_XINCREF(%s);'%(LOCAL_VAR % op.result.name)) return '\t'.join(result) @@ -619,7 +622,7 @@ if TYPE is not Void: result.append('%s = %s;' % (self.expr(op.result), self.expr(op.args[0]))) - if TYPE == PyObjPtr: + if NEED_OLD_EXTRA_REFS and TYPE == PyObjPtr: result.append('Py_XINCREF(%s);'%(LOCAL_VAR % op.result.name)) return '\t'.join(result) From ericvrp at codespeak.net Wed Mar 22 11:41:33 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 22 Mar 2006 11:41:33 +0100 (CET) Subject: [pypy-svn] r24777 - pypy/dist/pypy/translator/llvm Message-ID: <20060322104133.EFE5D1010F@code0.codespeak.net> Author: ericvrp Date: Wed Mar 22 11:41:21 2006 New Revision: 24777 Modified: pypy/dist/pypy/translator/llvm/codewriter.py Log: Do not use internal linkage for now. This didn't seem to make any performance difference anyway and it intervenes with using the LLVM JIT. Modified: pypy/dist/pypy/translator/llvm/codewriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/codewriter.py (original) +++ pypy/dist/pypy/translator/llvm/codewriter.py Wed Mar 22 11:41:21 2006 @@ -4,6 +4,7 @@ DEFAULT_TAIL = '' #/tail DEFAULT_CCONV = 'fastcc' #ccc/fastcc +DEFAULT_LINKAGE = '' #/internal (disabled for now because of the JIT) class CodeWriter(object): def __init__(self, file, db): @@ -59,8 +60,8 @@ self.newline() self._append(" %s:" % name) - def globalinstance(self, name, typeandata): - self._append("%s = %s global %s" % (name, "internal", typeandata)) + def globalinstance(self, name, typeandata, linkage=DEFAULT_LINKAGE): + self._append("%s = %sglobal %s" % (name, linkage, typeandata)) def typedef(self, name, type_): self._append("%s = type %s" % (name, type_)) @@ -99,9 +100,9 @@ self._indent("switch %s %s, label %%%s [%s ]" % (intty, cond, defaultdest, labels)) - def openfunc(self, decl, cconv=DEFAULT_CCONV): + def openfunc(self, decl, cconv=DEFAULT_CCONV, linkage=DEFAULT_LINKAGE): self.newline() - self._append("internal %s %s {" % (cconv, decl,)) + self._append("%s%s %s {" % (linkage, cconv, decl,)) def closefunc(self): self._append("}") From ericvrp at codespeak.net Wed Mar 22 11:58:27 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 22 Mar 2006 11:58:27 +0100 (CET) Subject: [pypy-svn] r24779 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060322105827.90C3310114@code0.codespeak.net> Author: ericvrp Date: Wed Mar 22 11:58:23 2006 New Revision: 24779 Added: pypy/dist/pypy/translator/llvm/pyllvm/build.py Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: ease build of pyllvm.so Added: pypy/dist/pypy/translator/llvm/pyllvm/build.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/build.py Wed Mar 22 11:58:23 2006 @@ -0,0 +1,11 @@ +try: + from pypy.translator.llvm.pyllvm import pyllvm +except: + try: + import sys + sys.argv = "setup.py build_ext -i".split() + from pypy.translator.llvm.pyllvm import setup + except: + import py + py.test.skip("pyllvm failed to build") + from pypy.translator.llvm.pyllvm import pyllvm Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Wed Mar 22 11:58:23 2006 @@ -1,16 +1,10 @@ import py from pypy.translator.llvm.buildllvm import llvm_is_on_path - if not llvm_is_on_path(): py.test.skip("llvm not found") -try: - from pypy.translator.llvm.pyllvm import pyllvm -except: - import sys - sys.argv = "setup.py build_ext -i".split() - from pypy.translator.llvm.pyllvm import setup - from pypy.translator.llvm.pyllvm import pyllvm +from pypy.translator.llvm.pyllvm.build import pyllvm + def test_execution_engine(): ee = pyllvm.get_ee() From arigo at codespeak.net Wed Mar 22 12:00:35 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 22 Mar 2006 12:00:35 +0100 (CET) Subject: [pypy-svn] r24780 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/ootypesystem rpython/test Message-ID: <20060322110035.6385B10114@code0.codespeak.net> Author: arigo Date: Wed Mar 22 12:00:31 2006 New Revision: 24780 Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/ootypesystem/rclass.py pypy/dist/pypy/rpython/rclass.py pypy/dist/pypy/rpython/rfloat.py pypy/dist/pypy/rpython/rmodel.py pypy/dist/pypy/rpython/rstr.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: * improve hash(tuple) in RPython, based on CPython's algo. * remove rtype_hash() everywhere and replace them with a generic implementation based on get_ll_hash_function(). Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Wed Mar 22 12:00:31 2006 @@ -246,6 +246,11 @@ def getanyitem(tup): return unionof(*tup.items) + def hash(tup): + for s_item in tup.items: + s_item.hash() # record that we need the hash of each item + return SomeInteger() + class __extend__(SomeList): Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Wed Mar 22 12:00:31 2006 @@ -377,12 +377,9 @@ def create_instance(self): return malloc(self.object_type, flavor=self.getflavor()) # pick flavor - def get_ll_eq_function(self): - return ll_inst_eq - def get_ll_hash_function(self): if self.classdef is None: - return None + raise TyperError, 'missing hash support flag in classdef' if self.rtyper.needs_hash_support(self.classdef): try: return self._ll_hash_function @@ -500,15 +497,6 @@ else: return instance_repr.getfield(vinst, '__class__', hop.llops) - def rtype_hash(self, hop): - if self.classdef is None: - raise TyperError, "hash() not supported for this class" - if self.rtyper.needs_hash_support(self.classdef): - vinst, = hop.inputargs(self) - return hop.gendirectcall(ll_inst_hash, vinst) - else: - return self.rbase.rtype_hash(hop) - def rtype_getattr(self, hop): attr = hop.args_s[1].const vinst, vattr = hop.inputargs(self, Void) @@ -637,9 +625,6 @@ cached = ins.hash_cache = id(ins) return cached -def ll_inst_eq(ins1, ins2): - return ins1 == ins2 - def ll_inst_type(obj): if obj: return obj.typeptr Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Wed Mar 22 12:00:31 2006 @@ -328,6 +328,9 @@ graph=graph) ootype.addMethods(self.lowleveltype, {mangled: m}) + def get_ll_hash_function(self): + return ll_inst_hash + def rtype_getattr(self, hop): v_inst, _ = hop.inputargs(self, ootype.Void) s_inst = hop.args_s[0] @@ -376,15 +379,6 @@ cmeta = inputconst(ootype.Void, "meta") return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE) - def rtype_hash(self, hop): - if self.classdef is None: - raise TyperError, "hash() not supported for this class" - if self.rtyper.needs_hash_support(self.classdef): - vinst, = hop.inputargs(self) - return hop.gendirectcall(ll_inst_hash, vinst) - else: - return self.baserepr.rtype_hash(hop) - def rtype_id(self, hop): vinst, = hop.inputargs(self) return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed) Modified: pypy/dist/pypy/rpython/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/rclass.py (original) +++ pypy/dist/pypy/rpython/rclass.py Wed Mar 22 12:00:31 2006 @@ -167,9 +167,6 @@ def rtype_type(self, hop): pass - def rtype_hash(self, hop): - pass - def rtype_getattr(self, hop): pass @@ -182,6 +179,9 @@ def ll_str(self, i): pass + def get_ll_eq_function(self): + return None # defaults to compare by identity ('==' on pointers) + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops): Modified: pypy/dist/pypy/rpython/rfloat.py ============================================================================== --- pypy/dist/pypy/rpython/rfloat.py (original) +++ pypy/dist/pypy/rpython/rfloat.py Wed Mar 22 12:00:31 2006 @@ -137,10 +137,6 @@ from pypy.rpython.module.ll_strtod import ll_strtod_formatd return ll_strtod_formatd(percent_f, f) - def rtype_hash(_, hop): - v_flt, = hop.inputargs(float_repr) - return hop.gendirectcall(ll_hash_float, v_flt) - percent_f = string_repr.convert_const("%f") TAKE_NEXT = float(2**31) @@ -158,6 +154,8 @@ v = (v - float(hipart)) * TAKE_NEXT x = hipart + int(v) + (expo << 15) return x +ll_hash_float.cache_in_dict = True + # # _________________________ Conversions _________________________ Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Wed Mar 22 12:00:31 2006 @@ -126,10 +126,19 @@ self, value)) return value - def get_ll_eq_function(self): + def get_ll_eq_function(self): + """Return an eq(x,y) function to use to compare two low-level + values of this Repr. + This can return None to mean that simply using '==' is fine. + """ raise TyperError, 'no equality function for %r' % self def get_ll_hash_function(self): + """Return a hash(x) function for low-level values of this Repr. + As a hint, the function can have a flag 'cache_in_dict=True' if it + makes non-trivial computations and its result should be cached in + dictionary entries. + """ raise TyperError, 'no hashing function for %r' % self def rtype_bltn_list(self, hop): @@ -175,6 +184,11 @@ # XXX return hop.genop('cast_ptr_to_int', [vobj], resulttype=Signed) + def rtype_hash(self, hop): + ll_hash = self.get_ll_hash_function() + v, = hop.inputargs(self) + return hop.gendirectcall(ll_hash, v) + def rtype_iter(self, hop): r_iter = self.make_iterator_repr() return r_iter.newiter(hop) Modified: pypy/dist/pypy/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/dist/pypy/rpython/rstr.py Wed Mar 22 12:00:31 2006 @@ -99,10 +99,6 @@ v_chr = hop.gendirectcall(ll_stritem_nonneg, v_str, c_zero) return hop.genop('cast_char_to_int', [v_chr], resulttype=Signed) - def rtype_hash(_, hop): - v_str, = hop.inputargs(string_repr) - return hop.gendirectcall(ll_strhash, v_str) - def rtype_method_startswith(_, hop): v_str, v_value = hop.inputargs(string_repr, string_repr) hop.exception_cannot_occur() Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Wed Mar 22 12:00:31 2006 @@ -9,6 +9,7 @@ from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.lltypesystem.lltype import \ Ptr, GcStruct, Void, Signed, malloc, typeOf, nullptr +from pypy.rpython.rarithmetic import intmask # ____________________________________________________________ # @@ -56,6 +57,7 @@ return ll_eq def gen_hash_function(items_r): + # based on CPython hash_funcs = [r_item.get_ll_hash_function() for r_item in items_r] key = tuple(hash_funcs) try: @@ -64,18 +66,22 @@ miniglobals = {} source = """ def ll_hash(t): - retval = 0 + retval = 0x345678 %s return retval """ body = [] + mult = 1000003 for i, hash_func in enumerate(hash_funcs): miniglobals['hash%d' % i] = hash_func - body.append("retval ^= hash%d(t.item%d)" % (i,i)) + body.append("retval = (retval ^ hash%d(t.item%d)) * %d" % + (i, i, mult)) + mult = intmask(mult + 82520 + 2*len(items_r)) body = ('\n'+' '*4).join(body) source = source % body exec source in miniglobals ll_hash = miniglobals['ll_hash'] + ll_hash.cache_in_dict = True _gen_hash_function_cache[key] = ll_hash return ll_hash Modified: pypy/dist/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rtuple.py (original) +++ pypy/dist/pypy/rpython/test/test_rtuple.py Wed Mar 22 12:00:31 2006 @@ -200,3 +200,11 @@ assert r_AB_tup.lowleveltype == r_BA_tup.lowleveltype + +def test_tuple_hash(): + def f(i, j): + return hash((i, j)) + + res1 = interpret(f, [12, 27]) + res2 = interpret(f, [27, 12]) + assert res1 != res2 From ericvrp at codespeak.net Wed Mar 22 12:19:24 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 22 Mar 2006 12:19:24 +0100 (CET) Subject: [pypy-svn] r24783 - in pypy/dist/pypy: jit/codegen jit/codegen/llvm jit/codegen/llvm/test translator/llvm/pyllvm Message-ID: <20060322111924.391A11011A@code0.codespeak.net> Author: ericvrp Date: Wed Mar 22 12:19:20 2006 New Revision: 24783 Added: pypy/dist/pypy/jit/codegen/ pypy/dist/pypy/jit/codegen/__init__.py pypy/dist/pypy/jit/codegen/llvm/ pypy/dist/pypy/jit/codegen/llvm/__init__.py pypy/dist/pypy/jit/codegen/llvm/jitcode.py pypy/dist/pypy/jit/codegen/llvm/rgenop.py pypy/dist/pypy/jit/codegen/llvm/test/ pypy/dist/pypy/jit/codegen/llvm/test/test_rgenop.py Modified: pypy/dist/pypy/translator/llvm/pyllvm/build.py Log: Generate JIT code from the graphs generated by rgenop.py Added: pypy/dist/pypy/jit/codegen/__init__.py ============================================================================== Added: pypy/dist/pypy/jit/codegen/llvm/__init__.py ============================================================================== Added: pypy/dist/pypy/jit/codegen/llvm/jitcode.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/jitcode.py Wed Mar 22 12:19:20 2006 @@ -0,0 +1,76 @@ +""" +All code for using LLVM's JIT in one place +""" + +import py +from pypy.translator.translator import TranslationContext +from pypy.translator.llvm.database import Database +from pypy.translator.llvm.codewriter import CodeWriter +from pypy.translator.llvm.opwriter import OpWriter +from pypy.translator.llvm.funcnode import FuncNode +from pypy.translator.llvm.gc import GcPolicy +from pypy.translator.llvm.exception import ExceptionPolicy +from pypy.translator.llvm.pyllvm.build import pyllvm +from cStringIO import StringIO + +from pypy.tool.ansi_print import ansi_log +log = py.log.Producer("llvm/jitcode") +py.log.setconsumer("llvm/jitcode", ansi_log) + + +# Custom database, codewriter and opwriter +class JITDatabase(Database): pass +class JITCodeWriter(CodeWriter): pass +class JITOpWriter(OpWriter): pass + +class GraphContainer(object): # XXX what should this really be? + def __init__(self, graph): + self.graph = graph + +# LLVM execution engine (llvm module) that is going to contain the code +ee = pyllvm.get_ee() + + +# Create a LLVM 'execution engine' which wrap the LLVM JIT +class JITcode(object): + + def __init__(self, typer): + self.typer = typer + self.db = JITDatabase(genllvm=None, translator=None) #XXX fake + self.db.gcpolicy = GcPolicy.new(self.db,'raw') + self.db.exceptionpolicy = ExceptionPolicy.new(self.db, 'explicit') + self.code = StringIO() + self.codewriter = JITCodeWriter(self.code, self.db) + self.opwriter = JITOpWriter(self.db, self.codewriter) + self.graph_ref = {} #name by which LLVM knowns a graph + + def backendoptimizations(self, graph, translator=None): + from pypy.translator.backendopt.removenoops import remove_same_as + from pypy.translator import simplify + from pypy.translator.unsimplify import remove_double_links + remove_same_as(graph) + simplify.eliminate_empty_blocks(graph) + simplify.transform_dead_op_vars(graph, translator) + remove_double_links(translator, graph) + #translator.checkgraph(graph) + + def codegen(self, graph): + self.backendoptimizations(graph) + node = FuncNode(self.db, GraphContainer(graph)) + node.writeimpl(self.codewriter) + log('code =' + self.code.getvalue()) + ee.parse(self.code.getvalue()) + return node.ref[1:] #strip of % prefix + + def eval_graph(self, graph, args=()): + """ + From a graph this generates llvm code that gets parsed. + It would be faster and use less memory to generate the code + without first generating the entire graph. + It would also be faster (probably) to extend pyllvm so blocks/instructions/etc. + could be added directly instead of using intermediate llvm sourcecode. + """ + log('eval_graph: %s(%s)' % (graph.name, args)) + if graph not in self.graph_ref: + self.graph_ref[graph] = self.codegen(graph) + return ee.call(self.graph_ref[graph], *args) Added: pypy/dist/pypy/jit/codegen/llvm/rgenop.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/rgenop.py Wed Mar 22 12:19:20 2006 @@ -0,0 +1,285 @@ +""" +Functions that generate flow graphs and operations. +The functions below produce L2 graphs, but they define an interface +that can be used to produce any other kind of graph. +""" + +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.objspace.flow import model as flowmodel +from pypy.translator.simplify import eliminate_empty_blocks, join_blocks +from pypy.rpython.module.support import init_opaque_object +from pypy.rpython.module.support import to_opaque_object, from_opaque_object +from pypy.rpython.module.support import from_rstr +from pypy.jit.codegen.llvm.jitcode import JITcode + + +# for debugging, sanity checks in non-RPython code +reveal = from_opaque_object + +def initblock(opaqueptr): + init_opaque_object(opaqueptr, flowmodel.Block([])) + +def newblock(): + blockcontainer = lltype.malloc(BLOCKCONTAINERTYPE) + initblock(blockcontainer.obj) + return blockcontainer + +def geninputarg(blockcontainer, gv_CONCRETE_TYPE): + block = from_opaque_object(blockcontainer.obj) + CONCRETE_TYPE = from_opaque_object(gv_CONCRETE_TYPE).value + v = flowmodel.Variable() + v.concretetype = CONCRETE_TYPE + block.inputargs.append(v) + return to_opaque_object(v) + +def _inputvars(vars): + if not isinstance(vars, list): + n = vars.ll_length() + vars = vars.ll_items() + else: + n = len(vars) + res = [] + for i in range(n): + v = from_opaque_object(vars[i]) + assert isinstance(v, (flowmodel.Constant, flowmodel.Variable)) + res.append(v) + return res + +# is opname a runtime value? +def genop(blockcontainer, opname, vars, gv_RESULT_TYPE): + if not isinstance(opname, str): + opname = from_rstr(opname) + block = from_opaque_object(blockcontainer.obj) + RESULT_TYPE = from_opaque_object(gv_RESULT_TYPE).value + opvars = _inputvars(vars) + v = flowmodel.Variable() + v.concretetype = RESULT_TYPE + op = flowmodel.SpaceOperation(opname, opvars, v) + block.operations.append(op) + return to_opaque_object(v) + +def gencallableconst(blockcontainer, name, targetcontainer, gv_FUNCTYPE): + # is name useful, is it runtime variable? + target = from_opaque_object(targetcontainer.obj) + FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value + fptr = lltype.functionptr(FUNCTYPE, name, + graph=_buildgraph(target)) + return genconst(fptr) + +def genconst(llvalue): + v = flowmodel.Constant(llvalue) + v.concretetype = lltype.typeOf(llvalue) + if v.concretetype == lltype.Void: # XXX genconst should not really be used for Void constants + assert not isinstance(llvalue, str) and not isinstance(llvalue, lltype.LowLevelType) + return to_opaque_object(v) + +def revealconst(T, gv_value): + c = from_opaque_object(gv_value) + assert isinstance(c, flowmodel.Constant) + if isinstance(T, lltype.Ptr): + return lltype.cast_pointer(T, c.value) + elif T == llmemory.Address: + return llmemory.cast_ptr_to_adr(c.value) + else: + return lltype.cast_primitive(T, c.value) + +# XXX +# temporary interface; it's unclera if genop itself should change to ease dinstinguishing +# Void special args from the rest. Or there should be variation for the ops involving them + +def placeholder(dummy): + c = flowmodel.Constant(dummy) + c.concretetype = lltype.Void + return to_opaque_object(c) + +def constFieldName(name): + assert isinstance(name, str) + c = flowmodel.Constant(name) + c.concretetype = lltype.Void + return to_opaque_object(c) + +def constTYPE(TYPE): + assert isinstance(TYPE, lltype.LowLevelType) + c = flowmodel.Constant(TYPE) + c.concretetype = lltype.Void + return to_opaque_object(c) + +def closeblock1(blockcontainer): + block = from_opaque_object(blockcontainer.obj) + link = flowmodel.Link([], None) + block.closeblock(link) + return to_opaque_object(link) + +def closeblock2into(blockcontainer, exitswitch, linkpair): + block = from_opaque_object(blockcontainer.obj) + exitswitch = from_opaque_object(exitswitch) + assert isinstance(exitswitch, flowmodel.Variable) + block.exitswitch = exitswitch + false_link = flowmodel.Link([], None) + false_link.exitcase = False + false_link.llexitcase = False + true_link = flowmodel.Link([], None) + true_link.exitcase = True + true_link.llexitcase = True + block.closeblock(false_link, true_link) + linkpair.item0 = to_opaque_object(false_link) + linkpair.item1 = to_opaque_object(true_link) + +def closeblock2(blockcontainer, exitswitch): + linkpair = lltype.malloc(LINKPAIR) + closeblock2into(blockcontainer, exitswitch, linkpair) + return linkpair + +def _closelink(link, vars, targetblock): + if isinstance(link, flowmodel.Link): + for v in vars: + assert isinstance(v, (flowmodel.Variable, flowmodel.Constant)) + assert ([v.concretetype for v in vars] == + [v.concretetype for v in targetblock.inputargs]) + link.args[:] = vars + link.target = targetblock + elif isinstance(link, flowmodel.FunctionGraph): + graph = link + graph.startblock = targetblock + targetblock.isstartblock = True + else: + raise TypeError + +def closelink(link, vars, targetblockcontainer): + link = from_opaque_object(link) + targetblock = from_opaque_object(targetblockcontainer.obj) + vars = _inputvars(vars) + return _closelink(link, vars, targetblock) + +def closereturnlink(link, returnvar): + returnvar = from_opaque_object(returnvar) + link = from_opaque_object(link) + v = flowmodel.Variable() + v.concretetype = returnvar.concretetype + pseudoreturnblock = flowmodel.Block([v]) + pseudoreturnblock.operations = () + _closelink(link, [returnvar], pseudoreturnblock) + +def _patchgraph(graph): + returntype = None + for link in graph.iterlinks(): + if link.target.operations == (): + assert len(link.args) == 1 # for now + if returntype is None: + returntype = link.target.inputargs[0].concretetype + else: + assert returntype == link.target.inputargs[0].concretetype + link.target = graph.returnblock + if returntype is None: + returntype = lltype.Void + graph.returnblock.inputargs[0].concretetype = returntype + +class PseudoRTyper(object): + def __init__(self): + from pypy.rpython.typesystem import LowLevelTypeSystem + self.type_system = LowLevelTypeSystem.instance + +def _buildgraph(block): + graph = flowmodel.FunctionGraph('generated', block) + _patchgraph(graph) + flowmodel.checkgraph(graph) + eliminate_empty_blocks(graph) + join_blocks(graph) + graph.rgenop = True + return graph + +def buildgraph(blockcontainer): + block = from_opaque_object(blockcontainer.obj) + return _buildgraph(block) + +def testgengraph(gengraph, args, viewbefore=False): + from pypy.rpython.llinterp import LLInterpreter + if viewbefore: + gengraph.show() + #llinterp = LLInterpreter(PseudoRTyper()) + #return llinterp.eval_graph(gengraph, args) + jitcode = JITcode(PseudoRTyper()) + return jitcode.eval_graph(gengraph, args) + +def runblock(blockcontainer, args, viewbefore=False): + graph = buildgraph(blockcontainer) + return testgengraph(graph, args, viewbefore) + +# ____________________________________________________________ +# RTyping of the above functions + +from pypy.rpython.extfunctable import declaretype, declareptrtype, declare + +blocktypeinfo = declaretype(flowmodel.Block, "Block") +consttypeinfo = declareptrtype(flowmodel.Constant, "ConstOrVar") +vartypeinfo = declareptrtype(flowmodel.Variable, "ConstOrVar") +vartypeinfo.set_lltype(consttypeinfo.get_lltype()) # force same lltype +linktypeinfo = declareptrtype(flowmodel.Link, "Link") + +CONSTORVAR = lltype.Ptr(consttypeinfo.get_lltype()) +BLOCKCONTAINERTYPE = blocktypeinfo.get_lltype() +BLOCK = lltype.Ptr(BLOCKCONTAINERTYPE) +LINK = lltype.Ptr(linktypeinfo.get_lltype()) + +fieldnames = ['item%d' % i for i in range(2)] +lltypes = [LINK]*2 +fields = tuple(zip(fieldnames, lltypes)) +LINKPAIR = lltype.GcStruct('tuple2', *fields) + +# helpers +def setannotation(func, TYPE): + func.compute_result_annotation = lambda *args_s: TYPE + +def setspecialize(func): + # for now + def specialize_as_direct_call(hop): + FUNCTYPE = lltype.FuncType([r.lowleveltype for r in hop.args_r], hop.r_result.lowleveltype) + args_v = hop.inputargs(*hop.args_r) + funcptr = lltype.functionptr(FUNCTYPE, func.__name__, _callable=func) + cfunc = hop.inputconst(lltype.Ptr(FUNCTYPE), funcptr) + return hop.genop('direct_call', [cfunc] + args_v, hop.r_result) + func.specialize = specialize_as_direct_call + +# annotations +from pypy.annotation import model as annmodel + +s_ConstOrVar = annmodel.SomePtr(CONSTORVAR)#annmodel.SomeExternalObject(flowmodel.Variable) +s_Link = annmodel.SomePtr(LINK)#annmodel.SomeExternalObject(flowmodel.Link) +s_LinkPair = annmodel.SomePtr(lltype.Ptr(LINKPAIR)) + +setannotation(initblock, None) +setannotation(geninputarg, s_ConstOrVar) +setannotation(genop, s_ConstOrVar) +setannotation(genconst, s_ConstOrVar) +revealconst.compute_result_annotation = lambda s_T, s_gv: annmodel.lltype_to_annotation(s_T.const) +setannotation(closeblock1, s_Link) +setannotation(closeblock2, s_LinkPair) +setannotation(closelink, None) +setannotation(closereturnlink, None) + +# specialize +setspecialize(initblock) +setspecialize(geninputarg) +setspecialize(genop) +setspecialize(genconst) +setspecialize(revealconst) +setspecialize(closeblock1) +setspecialize(closeblock2) +setspecialize(closelink) +setspecialize(closereturnlink) + +# XXX(for now) void constant constructors +setannotation(constFieldName, s_ConstOrVar) +setannotation(constTYPE, s_ConstOrVar) +setannotation(placeholder, s_ConstOrVar) + +def set_specialize_void_constant_constructor(func): + # for now + def specialize_as_constant(hop): + llvalue = func(hop.args_s[0].const) + return hop.inputconst(lltype.typeOf(llvalue), llvalue) + func.specialize = specialize_as_constant + +set_specialize_void_constant_constructor(placeholder) +set_specialize_void_constant_constructor(constFieldName) +set_specialize_void_constant_constructor(constTYPE) Added: pypy/dist/pypy/jit/codegen/llvm/test/test_rgenop.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_rgenop.py Wed Mar 22 12:19:20 2006 @@ -0,0 +1,166 @@ +from pypy.translator.llvm.buildllvm import llvm_is_on_path +if not llvm_is_on_path(): + import py + py.test.skip("llvm not found") + +from pypy.jit.codegen.llvm.rgenop import * +from pypy.rpython.lltypesystem.lltype import * +from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.module.support import from_opaque_object +from pypy.objspace.flow import model as flowmodel + + +def build_square(): + """def square(v0): return v0*v0""" + block = newblock() + v0 = geninputarg(block, constTYPE(Signed)) + v1 = genop(block, 'int_mul', [v0, v0], constTYPE(Signed)) + link = closeblock1(block) + closereturnlink(link, v1) + return block + +def test_square(): + block = build_square() + res = runblock(block, [17]) + assert res == 289 + +def test_rtype_newblock(): + def emptyblock(): + return newblock() + blockcontainer = interpret(emptyblock, []) + block = from_opaque_object(blockcontainer.obj) + assert isinstance(block, flowmodel.Block) + +def test_rtype_geninputarg(): + def onearg(): + block = newblock() + v0 = geninputarg(block, constTYPE(Signed)) + return v0 + opaquev = interpret(onearg, []) + v = from_opaque_object(opaquev) + assert isinstance(v, flowmodel.Variable) + +def test_rtype_build_square(): + blockcontainer = interpret(build_square, []) + res = runblock(blockcontainer, [17]) + assert res == 289 + +def build_if(): + """ + def f(v0): + if v0 < 0: + return 0 + else: + return v0 + """ + block = newblock() + v0 = geninputarg(block, constTYPE(Signed)) + const0 = genconst(0) + v1 = genop(block, 'int_lt', [v0, const0], constTYPE(Bool)) + exitspair = closeblock2(block, v1) + false_link, true_link = exitspair.item0, exitspair.item1 + closereturnlink(true_link, const0) + closereturnlink(false_link, v0) + return block + +def test_if(): + block = build_if() + res = runblock(block, [-1]) + assert res == 0 + res = runblock(block, [42]) + assert res == 42 + +def test_rtype_build_if(): + blockcontainer = interpret(build_if, []) + res = runblock(blockcontainer, [-1]) + assert res == 0 + res = runblock(blockcontainer, [42]) + assert res == 42 + +def build_loop(): + """ + def f(v0): + i = 1 + result = 1 + while i <= v0: + result *= i + i += 1 + return result + """ + block = newblock() + v0 = geninputarg(block, constTYPE(Signed)) + const1 = genconst(1) + link = closeblock1(block) + loopblock = newblock() + result0 = geninputarg(loopblock, constTYPE(Signed)) + i0 = geninputarg(loopblock, constTYPE(Signed)) + v1 = geninputarg(loopblock, constTYPE(Signed)) + closelink(link, [const1, const1, v0], loopblock) + const1 = genconst(1) + result1 = genop(loopblock, 'int_mul', [result0, i0], constTYPE(Signed)) + i1 = genop(loopblock, 'int_add', [i0, const1], constTYPE(Signed)) + v2 = genop(loopblock, 'int_le', [i1, v1], constTYPE(Bool)) + exitspair = closeblock2(loopblock, v2) + false_link, true_link = exitspair.item0, exitspair.item1 + closereturnlink(false_link, result1) + closelink(true_link, [result1, i1, v1], loopblock) + return block + +def test_loop(): + block = build_loop() + res = runblock(block, [0]) + assert res == 1 + res = runblock(block, [1]) + assert res == 1 + res = runblock(block, [7]) + assert res == 5040 + +def test_rtype_build_loop(): + blockcontainer = interpret(build_loop, []) + res = runblock(blockcontainer, [0]) + assert res == 1 + res = runblock(blockcontainer, [1]) + assert res == 1 + res = runblock(blockcontainer, [7]) + assert res == 5040 + +def test_rtype_void_constant_construction(): + def fieldname_foo(): + return constFieldName("foo") + res = interpret(fieldname_foo, []) + c = from_opaque_object(res) + assert isinstance(c, flowmodel.Constant) + assert c.concretetype == lltype.Void + assert c.value == "foo" + + def type_Signed(): + return constTYPE(lltype.Signed) + res = interpret(type_Signed, []) + c = from_opaque_object(res) + assert isinstance(c, flowmodel.Constant) + assert c.concretetype == lltype.Void + assert c.value == lltype.Signed + + def dummy(): + return placeholder(None) + res = interpret(dummy, []) + c = from_opaque_object(res) + assert isinstance(c, flowmodel.Constant) + assert c.concretetype == lltype.Void + assert c.value == None + +def test_rtype_revealcosnt(): + def hide_and_reveal(v): + gv = genconst(v) + return revealconst(lltype.Signed, gv) + res = interpret(hide_and_reveal, [42]) + assert res == 42 + + S = lltype.GcStruct('s', ('x', lltype.Signed)) + S_PTR = lltype.Ptr(S) + def hide_and_reveal_p(p): + gv = genconst(p) + return revealconst(S_PTR, gv) + s = malloc(S) + res = interpret(hide_and_reveal_p, [s]) + assert res == s Modified: pypy/dist/pypy/translator/llvm/pyllvm/build.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/build.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/build.py Wed Mar 22 12:19:20 2006 @@ -1,11 +1,5 @@ try: from pypy.translator.llvm.pyllvm import pyllvm except: - try: - import sys - sys.argv = "setup.py build_ext -i".split() - from pypy.translator.llvm.pyllvm import setup - except: - import py - py.test.skip("pyllvm failed to build") - from pypy.translator.llvm.pyllvm import pyllvm + import py + py.test.skip("pyllvm not found: run 'python setup.py build_ext -i' in translator/llvm/pyllvm") From arigo at codespeak.net Wed Mar 22 12:28:23 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 22 Mar 2006 12:28:23 +0100 (CET) Subject: [pypy-svn] r24785 - pypy/dist/pypy/rpython Message-ID: <20060322112823.E7349100CE@code0.codespeak.net> Author: arigo Date: Wed Mar 22 12:28:17 2006 New Revision: 24785 Modified: pypy/dist/pypy/rpython/raddress.py pypy/dist/pypy/rpython/rbool.py pypy/dist/pypy/rpython/rstr.py Log: The two AddressRepr.get_ll_*_function() were returning new function objects every time they were called. A couple of other details. Modified: pypy/dist/pypy/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/dist/pypy/rpython/raddress.py Wed Mar 22 12:28:17 2006 @@ -39,15 +39,13 @@ resulttype=lltype.Bool) def get_ll_eq_function(self): - def ll_eq(addr1, addr2): - return addr1 == addr2 - return ll_eq + return None def get_ll_hash_function(self): - def ll_hash(addr1): - return cast_adr_to_int(addr1) - return ll_hash + return ll_addrhash +def ll_addrhash(addr1): + return cast_adr_to_int(addr1) address_repr = AddressRepr() Modified: pypy/dist/pypy/rpython/rbool.py ============================================================================== --- pypy/dist/pypy/rpython/rbool.py (original) +++ pypy/dist/pypy/rpython/rbool.py Wed Mar 22 12:28:17 2006 @@ -23,9 +23,6 @@ raise TyperError("not a bool: %r" % (value,)) return value - def get_ll_eq_function(self): - return None - def rtype_is_true(_, hop): vlist = hop.inputargs(Bool) return vlist[0] Modified: pypy/dist/pypy/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/dist/pypy/rpython/rstr.py Wed Mar 22 12:28:17 2006 @@ -679,7 +679,7 @@ return len1 - len2 def ll_streq(s1, s2): - if not s1 and not s2: + if s1 == s2: # also if both are NULLs return True if not s1 or not s2: return False From mwh at codespeak.net Wed Mar 22 13:24:45 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 13:24:45 +0100 (CET) Subject: [pypy-svn] r24792 - pypy/branch/explicit-exceptions Message-ID: <20060322122445.EFD3E100FF@code0.codespeak.net> Author: mwh Date: Wed Mar 22 13:24:44 2006 New Revision: 24792 Added: pypy/branch/explicit-exceptions/ - copied from r24791, pypy/dist/pypy/ Log: make a branch to rip apart how we handle exceptions in genc and the gc transformer. From mwh at codespeak.net Wed Mar 22 13:26:26 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 13:26:26 +0100 (CET) Subject: [pypy-svn] r24793 - pypy/dist/pypy/doc/weekly Message-ID: <20060322122626.10966100FF@code0.codespeak.net> Author: mwh Date: Wed Mar 22 13:26:25 2006 New Revision: 24793 Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Log: small tweaks Modified: pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt ============================================================================== --- pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt (original) +++ pypy/dist/pypy/doc/weekly/summary-2006-03-15.txt Wed Mar 22 13:26:25 2006 @@ -74,10 +74,10 @@ root pointers. And then we banged our heads against the usual obscure bugs and -finally made it work. It turns out that debugging C that's generated -Python code that manipulates memory addresses directly is hard on the -brain... we need to get back to being able to run everything on the -memory simulator. +finally made it work. It turns out that debugging C that is generated +from Python code that manipulates memory addresses directly is hard on +the brain... we need to get back to being able to run everything on +the memory simulator. JIT Status ========== From mwh at codespeak.net Wed Mar 22 13:34:41 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 13:34:41 +0100 (CET) Subject: [pypy-svn] r24794 - pypy/dist/pypy/objspace/flow Message-ID: <20060322123441.EE327100FF@code0.codespeak.net> Author: mwh Date: Wed Mar 22 13:34:35 2006 New Revision: 24794 Modified: pypy/dist/pypy/objspace/flow/model.py Log: don't use id dictionaries in iterlinks(), itergraphs(), Blocks don't define __eq__ or __cmp__ so there's no need. Also, not doing so is ever-so-slightly quicker. Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Wed Mar 22 13:34:35 2006 @@ -77,25 +77,25 @@ def iterblocks(self): block = self.startblock yield block - seen = {id(block): True} + seen = {block: True} stack = list(block.exits[::-1]) while stack: block = stack.pop().target - if id(block) not in seen: + if block not in seen: yield block - seen[id(block)] = True + seen[block] = True stack += block.exits[::-1] def iterlinks(self): block = self.startblock - seen = {id(block): True} + seen = {block: True} stack = list(block.exits[::-1]) while stack: link = stack.pop() yield link block = link.target - if id(block) not in seen: - seen[id(block)] = True + if block not in seen: + seen[block] = True stack += block.exits[::-1] def show(self): From mwh at codespeak.net Wed Mar 22 13:36:27 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 13:36:27 +0100 (CET) Subject: [pypy-svn] r24795 - pypy/dist/pypy/translator/c Message-ID: <20060322123627.80A82100FF@code0.codespeak.net> Author: mwh Date: Wed Mar 22 13:36:26 2006 New Revision: 24795 Modified: pypy/dist/pypy/translator/c/database.py Log: add a check that we don't call getcontainernode() on a new container too late. Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Wed Mar 22 13:36:26 2006 @@ -107,6 +107,7 @@ try: node = self.containernodes[container] except KeyError: + assert not self.completed T = typeOf(container) if isinstance(T, (lltype.Array, lltype.Struct)): if hasattr(self.gctransformer, 'consider_constant'): From mwh at codespeak.net Wed Mar 22 14:09:56 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 14:09:56 +0100 (CET) Subject: [pypy-svn] r24797 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060322130956.78F9D10124@code0.codespeak.net> Author: mwh Date: Wed Mar 22 14:09:49 2006 New Revision: 24797 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: enable tests on the branch -- run at your own risk :) Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Wed Mar 22 14:09:49 2006 @@ -59,7 +59,7 @@ result = interpret(foo, []) assert result == 1 f = compile_func(foo, []) -# assert f() == 1 + assert f() == 1 def test_passthrough(): def one(x): @@ -72,7 +72,7 @@ t, g = transform_func(foo, []) assert len(list(g.iterblocks())) == 4 f = compile_func(foo, []) -# py.test.raises(ValueError, f) + py.test.raises(ValueError, f) def test_catches(): def one(x): @@ -98,16 +98,16 @@ f = compile_func(foo, [int]) result = interpret(foo, [6]) assert result == 2 -# result = f(6) -# assert result == 2 + result = f(6) + assert result == 2 result = interpret(foo, [7]) assert result == 4 -# result = f(7) -# assert result == 4 + result = f(7) + assert result == 4 result = interpret(foo, [8]) assert result == 2 -# result = f(8) -# assert result == 2 + result = f(8) + assert result == 2 def test_raises(): @@ -117,6 +117,6 @@ t, g = transform_func(foo, [int]) assert len(list(g.iterblocks())) == 4 f = compile_func(foo, [int]) -# f(0) -# py.test.raises(ValueError, f, 0) + f(0) + py.test.raises(ValueError, f, 1) From mwh at codespeak.net Wed Mar 22 14:10:21 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 14:10:21 +0100 (CET) Subject: [pypy-svn] r24798 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060322131021.D55B810124@code0.codespeak.net> Author: mwh Date: Wed Mar 22 14:10:20 2006 New Revision: 24798 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: use boehm gc policy for now, less likely to segfault :) Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Wed Mar 22 14:10:20 2006 @@ -38,7 +38,7 @@ t.buildrtyper().specialize() etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.transform_completely() - builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.RefcountingGcPolicy) + builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.BoehmGcPolicy) builder.generate_source() skip_missing_compiler(builder.compile) builder.import_module() From mwh at codespeak.net Wed Mar 22 14:58:03 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 14:58:03 +0100 (CET) Subject: [pypy-svn] r24799 - pypy/branch/explicit-exceptions/rpython/memory Message-ID: <20060322135803.BCE0F10127@code0.codespeak.net> Author: mwh Date: Wed Mar 22 14:58:02 2006 New Revision: 24799 Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Log: don't overwrite a cleanup in the gc transformer. this is a temporary hack... Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/memory/gctransform.py (original) +++ pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Wed Mar 22 14:58:02 2006 @@ -133,9 +133,11 @@ cleanup_on_exception.extend(self.pop_alive(var)) cleanup_on_exception = tuple(cleanup_on_exception) livevars2cleanup[tuple(livevars)] = cleanup_on_exception - op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception + if not hasattr(op, 'cleanup'): + op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception else: - op.cleanup = None + if not hasattr(op, 'cleanup'): + op.cleanup = None op = ops[-1] if var_needsgc(op.result): if op.opname not in ('direct_call', 'indirect_call') and not var_ispyobj(op.result): From antocuni at codespeak.net Wed Mar 22 15:02:03 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 22 Mar 2006 15:02:03 +0100 (CET) Subject: [pypy-svn] r24800 - pypy/dist/pypy/translator/cli Message-ID: <20060322140203.1E15C10127@code0.codespeak.net> Author: antocuni Date: Wed Mar 22 15:01:42 2006 New Revision: 24800 Added: pypy/dist/pypy/translator/cli/ - copied from r24799, user/antocuni/pypy-antocuni/pypy/translator/cli/ Log: Initial commit of the CLI backend From ac at codespeak.net Wed Mar 22 15:54:32 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 22 Mar 2006 15:54:32 +0100 (CET) Subject: [pypy-svn] r24801 - in pypy/dist/pypy/interpreter: . astcompiler test Message-ID: <20060322145432.AE5CB10132@code0.codespeak.net> Author: ac Date: Wed Mar 22 15:54:31 2006 New Revision: 24801 Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/test/test_syntax.py Log: Fix with-statement to match new definition. Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Wed Mar 22 15:54:31 2006 @@ -574,7 +574,7 @@ self.nextBlock(body) self._implicitNameOp('LOAD', var) self._implicitNameOp('DELETE', var) - node.var.accept(self) + node.var.accept(self) else: self.emit('POP_TOP') self.emitop_block('SETUP_FINALLY', finally_block) @@ -593,8 +593,6 @@ self._implicitNameOp('DELETE', exit) self.emit('WITH_CLEANUP') - self.emitop_int('CALL_FUNCTION', 3) - self.emit('POP_TOP') self.emit('END_FINALLY') self.setups.pop() Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Wed Mar 22 15:54:31 2006 @@ -46,6 +46,15 @@ raise IndexError, 'not enough entries in stack' return self.items[~position] + def set_top(self, value, position=0): + """'position' is 0 for the top of the stack, 1 for the item below, + and so on. It must not be negative.""" + if position < 0: + raise ValueError, 'negative stack position' + if position >= len(self.items): + raise IndexError, 'not enough entries in stack' + self.items[~position] = value + def depth(self): return len(self.items) @@ -98,6 +107,10 @@ # for a fixed stack, we assume correct indices return self.items[self.ptr + ~position] + def set_top(self, value, position=0): + # for a fixed stack, we assume correct indices + self.items[self.ptr + ~position] = value + def depth(self): return self.ptr Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Mar 22 15:54:31 2006 @@ -639,17 +639,24 @@ def WITH_CLEANUP(f): # see comment in END_FINALLY for stack state - w_unroller = f.valuestack.top(3) + w_exitfunc = f.valuestack.pop() + w_unroller = f.valuestack.top(2) unroller = f.space.interpclass_w(w_unroller) if (isinstance(unroller, pyframe.SuspendedUnroller) and isinstance(unroller.flowexc, pyframe.SApplicationException)): - f.valuestack.push(unroller.flowexc.operr.w_type) - f.valuestack.push(unroller.flowexc.operr.w_value) - f.valuestack.push(unroller.flowexc.operr.application_traceback) + operr = unroller.flowexc.operr + w_result = f.space.call_function(w_exitfunc, + operr.w_type, + operr.w_value, + operr.application_traceback) + if f.space.is_true(w_result): + # __exit__() returned True -> Swallow the exception. + f.valuestack.set_top(f.space.w_None, 2) else: - f.valuestack.push(f.space.w_None) - f.valuestack.push(f.space.w_None) - f.valuestack.push(f.space.w_None) + f.space.call_function(w_exitfunc, + f.space.w_None, + f.space.w_None, + f.space.w_None) def call_function(f, oparg, w_star=None, w_starstar=None): n_arguments = oparg & 0xff Modified: pypy/dist/pypy/interpreter/test/test_syntax.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_syntax.py (original) +++ pypy/dist/pypy/interpreter/test/test_syntax.py Wed Mar 22 15:54:31 2006 @@ -257,7 +257,7 @@ assert x == expected class AppTestWith: - def test_with_1(self): + def test_with_simple(self): s = """from __future__ import with_statement if 1: @@ -291,7 +291,7 @@ assert acontext.calls == '__context__ __enter__ __exit__'.split() - def test_with_2(self): + def test_with_as_var(self): s = """from __future__ import with_statement if 1: @@ -327,7 +327,7 @@ assert acontextfact.exit_params == (None, None, None) assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() - def test_with_3(self): + def test_with_raise_exception(self): s = """from __future__ import with_statement if 1: @@ -371,8 +371,49 @@ assert acontextfact.exit_params[0:2] == (RuntimeError, error) import types assert isinstance(acontextfact.exit_params[2], types.TracebackType) - - def test_with_4(self): + + def test_with_swallow_exception(self): + + s = """from __future__ import with_statement +if 1: + class ContextFactory: + + class Context: + def __init__(self, factory): + self.factory = factory + + def __enter__(self): + self.factory.calls.append('__enter__') + return self.factory.calls + + def __exit__(self, exc_type, exc_value, exc_tb): + self.factory.calls.append('__exit__') + self.factory.exit_params = (exc_type, exc_value, exc_tb) + return True + + def __init__(self): + self.calls = list() + self.context = self.Context(self) + + def __context__(self): + self.calls.append('__context__') + return self.context + + acontextfact = ContextFactory() + error = RuntimeError('With Test') + with acontextfact as avar: + avar.append('__body__') + raise error + avar.append('__after_raise__') + """ + exec s + + assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() + assert acontextfact.exit_params[0:2] == (RuntimeError, error) + import types + assert isinstance(acontextfact.exit_params[2], types.TracebackType) + + def test_with_break(self): s = """from __future__ import with_statement if 1: @@ -413,7 +454,7 @@ assert acontextfact.calls == '__context__ __enter__ __body__ __exit__'.split() assert acontextfact.exit_params == (None, None, None) - def test_with_5(self): + def test_with_continue(self): s = """from __future__ import with_statement if 1: @@ -445,7 +486,7 @@ with acontextfact as avar: avar.append('__body__') continue - avar.append('__after_break__') + avar.append('__after_continue__') else: avar.append('__continue__') """ @@ -454,8 +495,7 @@ assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __continue__'.split() assert acontextfact.exit_params == (None, None, None) - def test_with_6(self): - + def test_with_return(self): s = """from __future__ import with_statement if 1: class ContextFactory: @@ -494,10 +534,10 @@ assert acontextfact.calls == '__context__ __enter__ __body__ __exit__ __return__'.split() assert acontextfact.exit_params == (None, None, None) - def test_with_7(self): + def test_with_as_identifier(self): exec "with = 9" - def test_with_8(self): + def test_with_as_keyword(self): try: exec "from __future__ import with_statement\nwith = 9" except SyntaxError: @@ -505,7 +545,7 @@ else: assert False, 'Assignment to with did not raise SyntaxError' - def test_with_9(self): + def test_with_propagate_compileflag(self): s = """from __future__ import with_statement if 1: compile('''with x: From bea at codespeak.net Wed Mar 22 16:59:34 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Wed, 22 Mar 2006 16:59:34 +0100 (CET) Subject: [pypy-svn] r24806 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060322155934.B55B410132@code0.codespeak.net> Author: bea Date: Wed Mar 22 16:59:28 2006 New Revision: 24806 Added: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt Log: Tokyo sprint announcement minus the technical goals and topics - Arre and Samuele - do your stuff ;-)and then we ship it.... Added: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt Wed Mar 22 16:59:28 2006 @@ -0,0 +1,136 @@ +Tokyo PyPy Sprint: 23rd - 29th April 2006 +============================================================ + +The next PyPy sprint is scheduled to take place 23rd- 29th April 2006 +(Sunday-Saturday) in Akihabara, Tokyo, Japan. We will together with +FSIJ (Free Software Initiative of Japan) aim to promote Python and PyPy. +We therefor invite Japanese hackers knowledgeable in Python to join our sprint! +We'll give newcomer-friendly introductions and the focus will +mainly be XXX. To learn more about the new Python-in-Python implementation look here: + + http://codespeak.net/pypy + +For this sprint we are particularly interested in meeting and coding on PyPy together +with interested Japanese Python hackers. Please register your interest at pypy-sprint at codespeak.net +as soon as possible and we will help with any questions regarding getting started, pointing +to relevant documentation etc. + +The PyPy team is curious and interested in the experience of hacking code for embedded devices +and would love to discuss and get feedback on optimisation efforts and the current state of PyPy. + +Goals and topics of the sprint +------------------------------ + +XXX + + - XXX + - XXX + - XXX + - whatever participants want to do with PyPy (please send + suggestions to the mailing list before to allow us to plan + and give feedback) + + +Location & Accomodation +------------------------ + +The sprint will be held at National Institute of AIST + (National Institute of Advanced Industrial Science and Technology, + http://www.aist.go.jp/index_en.html), Akihahabara (the technical gadget +district in Tokyo). Yutaka Niibe is our contact person there, +helping with arranging facilities. Niibe is the chairman of FSIJ and they have +invited us to sprint in Tokyo and we are very grateful for the help and interest +we have recieved so far. + +The facilities we are sprinting in are located here: + + http://www.gtrc.aist.go.jp/en/access/index.html#Akihabara + + +The actual address is: +Akihabara Dai Bldg , 1-18-13 Sotokanda, Chiyoda-ku, Tokyo 101-0021 Japan +Phone: +81-3-5298-4729 + +Hotel areas - we are recommended to book hotels in Ueno and Asakusa (old town), +from those areas there are only two metro stops to Akihabara. Please note that +hotelrooms in Tokyo are often very small. + + http://www.wh-rsv.com/english/akihabara/index.html (nearest hotel to sprint location) + http://www.greenhotel.co.jp/ochanomizu_e.html + http://www.ohgai.co.jp/index-e.html (Ueno) + http://www.toyoko-inn.com/e_hotel/00012/index.html (Asakusa) + http://www.hotelnewkanda.com/ (second nearest, but no english page) + +Here is a url for booking hotels with not too unreasonable rates (see map): +http://japan-hotelguide.com/hotels/Japan/Tokyo/index.htm + +For more general tourist information about travelling to Japan and Tokyo - please see: +http://www.jnto.go.jp/eng/ +http://www.japantravelinfo.com/ (really useful information regarding airfares, hotels, currency, phones etc etc) + +Comments on the weather: In end April it is ca 20 degrees Celsius. + + +Exact times +----------- + +The public PyPy sprint is held Sunday 23rd - Saturday 29th April 2006. +Hours will be from 10:00 until people have had enough. It's a good idea +to arrive a day before the sprint starts and leave a day later. Sometimes people +cannot stay for the whole sprint - you are welcome even if you can only stay +for a day or a few days. + +Sunday: Starting at 10:00. This day is focused on getting to know PyPy enought to +start to participate. We will hold a PyPy tutorial and an architectural overview. +Planning meeting for the work to be done during the week and grouping of developers (pairs +or groups mixing new participants with core developers). + +Dinner in the evening (Yutaka will arrange a place for us to go to). + +Monday-Tuesday: Starting at 10:00 with status meetings. Possible regrouping +depending on the interest and progress of the various teams. + +Wednesday: Breakday (coding is allowed although we recommend taking a break). + +Thursday-Saturday: Starting at 10:00 with status meetings. Possible regrouping +depending on the interest and progress of the various teams. Ending on Saturday with +a Closure session - summing of the work and planning work to be done until the next sprint. + + +Network, Food, currency +------------------------ + +We will have access to WiFi at AIST - please make sure you have wlan capabilities. + +Electricity outlets: 100V (adapters needed for european standard). + +Currency is Japanese yen. There are Citibank cash machines that +accepts cash withdrawals from the major cards such as VISA and Mastercard. +But it is a good idea to bring cash. + +Also note that cell phones (european) are not very compatible with the Japanese +network. There are possibilities for 3G phones to hire a phone and put your simcard +in there. At the airport (both Kansai and Narita) there are information and places +were this can be arranged (to a cost of course). + +Food: well - japanese food is great (wether it is sushi, sashimi, tempura, sukiyaki, teriyaki.... +Eating out is not that much differently prized +than any large european town. There are of course restaurants serving +other food than japanese (chinese, korean, McDonalds ;-). +Please also note that vegetables and fruit is quite expensive in Japan. + +For more information - see tourist url:s above. + +Registration etc.pp. +-------------------- + +Please subscribe to the `PyPy sprint mailing list`_, introduce yourself +and post a note that you want to come. Feel free to ask any questions +there! There also is a separate `Tokyo people`_ page tracking who is +already thought to come. If you have commit rights on codespeak then +you can modify yourself a checkout of + + http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt + +.. _`PyPy sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint +.. _`Tokyo people`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/people.html From mwh at codespeak.net Wed Mar 22 19:46:57 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 19:46:57 +0100 (CET) Subject: [pypy-svn] r24813 - in pypy/branch/explicit-exceptions/translator/c: . test Message-ID: <20060322184657.3F7FD10150@code0.codespeak.net> Author: mwh Date: Wed Mar 22 19:46:55 2006 New Revision: 24813 Modified: pypy/branch/explicit-exceptions/translator/c/database.py pypy/branch/explicit-exceptions/translator/c/funcgen.py pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: over-confidence: apply the exception transform to all graphs. Modified: pypy/branch/explicit-exceptions/translator/c/database.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/database.py (original) +++ pypy/branch/explicit-exceptions/translator/c/database.py Wed Mar 22 19:46:55 2006 @@ -13,6 +13,7 @@ from pypy.translator.c.pyobj import PyObjMaker from pypy.translator.c.support import log from pypy.translator.c.extfunc import do_the_getting +from pypy.translator.c.exceptiontransform import ExceptionTransformer # ____________________________________________________________ @@ -38,6 +39,7 @@ if gcpolicy is None: from pypy.translator.c import gc gcpolicy = gc.RefcountingGcPolicy + self.exctransformer = ExceptionTransformer(translator) self.gcpolicy = gcpolicy(self, thread_enabled) self.gctransformer = gcpolicy.transformerclass(translator) self.completed = False Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Wed Mar 22 19:46:55 2006 @@ -36,6 +36,8 @@ self.gcpolicy = db.gcpolicy self.cpython_exc = cpython_exc self.functionname = functionname + # apply the exception transformation + self.db.exctransformer.create_exception_handling(self.graph) # apply the gc transformation self.db.gctransformer.transform_graph(self.graph) #self.graph.show() Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Wed Mar 22 19:46:55 2006 @@ -36,8 +36,8 @@ t = TranslationContext() t.buildannotator().build_types(fn, inputtypes) t.buildrtyper().specialize() - etrafo = exceptiontransform.ExceptionTransformer(t) - etrafo.transform_completely() +## etrafo = exceptiontransform.ExceptionTransformer(t) +## etrafo.transform_completely() builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.BoehmGcPolicy) builder.generate_source() skip_missing_compiler(builder.compile) From mwh at codespeak.net Wed Mar 22 20:00:24 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 20:00:24 +0100 (CET) Subject: [pypy-svn] r24814 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060322190024.2D25710143@code0.codespeak.net> Author: mwh Date: Wed Mar 22 20:00:22 2006 New Revision: 24814 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: add some weird and wonderful operations to lloperation. Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Wed Mar 22 20:00:22 2006 @@ -276,12 +276,16 @@ 'gc_fetch_exception': LLOp(), 'gc_restore_exception': LLOp(), 'gc_call_rtti_destructor': LLOp(), + 'gc_push_alive_pyobj': LLOp(), + 'gc_pop_alive_pyobj': LLOp(), # __________ misc operations __________ 'keepalive': LLOp(), 'same_as': LLOp(canfold=True), 'hint': LLOp(), + 'check_no_more_arg': LLOp(canraise=(Exception,)), + 'decode_arg': LLOp(canraise=(Exception,)), } # __________ operations on PyObjects __________ From tismer at codespeak.net Wed Mar 22 20:12:11 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 22 Mar 2006 20:12:11 +0100 (CET) Subject: [pypy-svn] r24815 - pypy/extradoc/planning Message-ID: <20060322191211.E7CD210147@code0.codespeak.net> Author: tismer Date: Wed Mar 22 20:12:08 2006 New Revision: 24815 Modified: pypy/extradoc/planning/sprint-planning.txt Log: updated dates for Leysin Modified: pypy/extradoc/planning/sprint-planning.txt ============================================================================== --- pypy/extradoc/planning/sprint-planning.txt (original) +++ pypy/extradoc/planning/sprint-planning.txt Wed Mar 22 20:12:08 2006 @@ -37,7 +37,7 @@ April/Leysin ------------- -Time & location: ?, Leysin, Switzerland +Time & location: 3rd to 9th of March, Leysin, Switzerland Nature: closed/core From tismer at codespeak.net Wed Mar 22 20:23:37 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 22 Mar 2006 20:23:37 +0100 (CET) Subject: [pypy-svn] r24816 - pypy/extradoc/planning Message-ID: <20060322192337.692EE10147@code0.codespeak.net> Author: tismer Date: Wed Mar 22 20:23:29 2006 New Revision: 24816 Modified: pypy/extradoc/planning/sprint-planning.txt Log: hum, this is April :-) Modified: pypy/extradoc/planning/sprint-planning.txt ============================================================================== --- pypy/extradoc/planning/sprint-planning.txt (original) +++ pypy/extradoc/planning/sprint-planning.txt Wed Mar 22 20:23:29 2006 @@ -37,7 +37,7 @@ April/Leysin ------------- -Time & location: 3rd to 9th of March, Leysin, Switzerland +Time & location: 3rd to 9th of April, 2006, Leysin, Switzerland Nature: closed/core From mwh at codespeak.net Wed Mar 22 20:58:38 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 22 Mar 2006 20:58:38 +0100 (CET) Subject: [pypy-svn] r24817 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060322195838.512131014D@code0.codespeak.net> Author: mwh Date: Wed Mar 22 20:58:27 2006 New Revision: 24817 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: gc_{un,}protect for lloperation Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Wed Mar 22 20:58:27 2006 @@ -278,6 +278,8 @@ 'gc_call_rtti_destructor': LLOp(), 'gc_push_alive_pyobj': LLOp(), 'gc_pop_alive_pyobj': LLOp(), + 'gc_protect': LLOp(), + 'gc_unprotect': LLOp(), # __________ misc operations __________ From ericvrp at codespeak.net Wed Mar 22 21:02:55 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 22 Mar 2006 21:02:55 +0100 (CET) Subject: [pypy-svn] r24818 - pypy/dist/pypy/translator/llvm/pyllvm/test Message-ID: <20060322200255.7934010145@code0.codespeak.net> Author: ericvrp Date: Wed Mar 22 21:02:54 2006 New Revision: 24818 Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Added pyllvm test and some todo's Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Wed Mar 22 21:02:54 2006 @@ -31,24 +31,34 @@ ee.parse(codepath.join("hello.s").read()) functions = ee.functions() assert len(functions) == 2 - for ii in functions: - assert len(ii) == 3 - assert ii[0] > 0 - assert ii[1] in 'gethellostr', 'hello' - assert len(ii[2]) == 0 + for function in functions: + returnId, name, args = function + assert len(function) == 3 + assert returnId > 0 + assert name in ('gethellostr', 'hello') + assert len(args) == 0 -def test_call1(): +def test_call_parse_once(): ee = get_fresh_ee() ee.parse(codepath.join("hello.s").read()) assert ee.call("hello") == 0 assert ee.call("gethellostr") == "hello world\n" - try: - ee.call("gethellostrx") - except: - pass - try: - ee.call("gethellostr", 1) - except: - pass + py.test.raises(Exception, ee.call, "gethellostrx") + py.test.raises(Exception, ee.call, "gethellostr", 1) + +def test_call_parse_twice(): + ee = get_fresh_ee() + ee.parse(codepath.join("hello.s").read()) + assert ee.call("gethellostr") == "hello world\n" ee.parse(codepath.join("addnumbers.s").read()) assert ee.call("add", 10, 32) == 42 + assert ee.call("gethellostr") == "hello world\n" + +def TODOtest_call_between_parsed_code(): + pass + +def TODOtest_share_data_between_parsed_code(): + pass + +def TODOtest_delete_function(): + pass From cfbolz at codespeak.net Wed Mar 22 21:21:49 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 22 Mar 2006 21:21:49 +0100 (CET) Subject: [pypy-svn] r24819 - in pypy/branch/explicit-exceptions/rpython/memory: . test Message-ID: <20060322202149.96FE610147@code0.codespeak.net> Author: cfbolz Date: Wed Mar 22 21:21:38 2006 New Revision: 24819 Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py pypy/branch/explicit-exceptions/rpython/memory/test/test_gctransform.py Log: steps towards removing the op.cleanup hack. probably breaks almost everything, but test_gctransform at least still works. Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/memory/gctransform.py (original) +++ pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Wed Mar 22 21:21:38 2006 @@ -92,7 +92,6 @@ def transform_block(self, block): newops = [] livevars = [var for var in block.inputargs if var_needsgc(var)] - livevars2cleanup = {} newops = [] if block.isstartblock: for var in block.inputargs: @@ -102,86 +101,31 @@ # graph-transforming capabilities of the RTyper instead, as we # seem to run into all the same problems as the ones we already # had to solve there. - has_exception_handler = block.exitswitch == c_last_exception for i, op in enumerate(block.operations): num_ops_after_exc_raising = 0 - res = self.replacement_operations(op, livevars, block) - try: - ops, cleanup_before_exception = res - except ValueError: - ops, cleanup_before_exception, num_ops_after_exc_raising = res + ops = self.replacement_operations(op, livevars, block) if not ops: continue # may happen when we eat gc_protect/gc_unprotect. newops.extend(ops) origname = op.opname - op = ops[-1-num_ops_after_exc_raising] - # look into the table of all operations to check whether op is - # expected to raise. if it is not in the table or the last - # operation in a block with exception catching, we assume it can - if (op.opname not in LL_OPERATIONS or - op.opname not in NEVER_RAISING_OPS or - (has_exception_handler and i == len(block.operations) - 1)): - can_raise = True - else: - can_raise = bool(LL_OPERATIONS[op.opname].canraise) - if can_raise: - if tuple(livevars) in livevars2cleanup: - cleanup_on_exception = livevars2cleanup[tuple(livevars)] - else: - cleanup_on_exception = [] - for var in livevars: - cleanup_on_exception.extend(self.pop_alive(var)) - cleanup_on_exception = tuple(cleanup_on_exception) - livevars2cleanup[tuple(livevars)] = cleanup_on_exception - if not hasattr(op, 'cleanup'): - op.cleanup = tuple(cleanup_before_exception), cleanup_on_exception - else: - if not hasattr(op, 'cleanup'): - op.cleanup = None op = ops[-1] if var_needsgc(op.result): if op.opname not in ('direct_call', 'indirect_call') and not var_ispyobj(op.result): lst = list(self.push_alive(op.result)) newops.extend(lst) - num_ops_after_exc_raising += len(lst) livevars.append(op.result) if len(block.exits) == 0: # everything is fine already for returnblocks and exceptblocks pass else: - if block.exitswitch is c_last_exception: - # if we're in a try block, the last operation must - # remain the last operation, so don't add a pop_alive - # to the block, even if the variable dies in all - # linked blocks. - deadinallexits = sets.Set([]) - if num_ops_after_exc_raising > 0: - # No place to put the remaining pending operations! - # Need a new block along the non-exceptional link. - # XXX test this. - tail = newops[-num_ops_after_exc_raising:] - del newops[-num_ops_after_exc_raising:] - link = block.exits[0] - assert link.exitcase is None - insert_empty_block(self.translator, link, tail) - else: - deadinallexits = sets.Set(livevars) - for link in block.exits: - deadinallexits.difference_update(sets.Set(link.args)) + assert block.exitswitch is not c_last_exception + deadinallexits = sets.Set(livevars) + for link in block.exits: + deadinallexits.difference_update(sets.Set(link.args)) for var in deadinallexits: newops.extend(self.pop_alive(var)) for link in block.exits: livecounts = dict.fromkeys(sets.Set(livevars) - deadinallexits, 1) - if (block.exitswitch is c_last_exception and - link.exitcase is not None): - if livevars and livevars[-1] is block.operations[-1].result: - # if the last operation in the block raised an - # exception, it can't have returned anything that - # might need pop_aliving. - del livecounts[livevars[-1]] - for v in link.last_exception, link.last_exc_value: - if var_needsgc(v): - livecounts[v] = 1 for v in link.args: if v in livecounts: livecounts[v] -= 1 @@ -197,7 +141,7 @@ if m: return m(op, livevars, block) else: - return [op], [] + return [op] def push_alive(self, var): @@ -384,35 +328,37 @@ """ protect this object from gc (make it immortal) """ newops = self.push_alive(op.args[0]) newops[-1].result = op.result - return newops, [] + return newops def replace_gc_unprotect(self, op, livevars, block): """ get this object back into gc control """ newops = self.pop_alive(op.args[0]) newops[-1].result = op.result - return newops, [] + return newops def replace_setfield(self, op, livevars, block): if not var_needsgc(op.args[2]): - return [op], [] + return [op] oldval = varoftype(op.args[2].concretetype) getoldvalop = SpaceOperation("getfield", [op.args[0], op.args[1]], oldval) result = [getoldvalop] result.extend(self.push_alive(op.args[2])) result.append(op) - return result, self.pop_alive(oldval) + result.extend(self.pop_alive(oldval)) + return result def replace_setarrayitem(self, op, livevars, block): if not var_needsgc(op.args[2]): - return [op], [] + return [op] oldval = varoftype(op.args[2].concretetype) getoldvalop = SpaceOperation("getarrayitem", [op.args[0], op.args[1]], oldval) result = [getoldvalop] result.extend(self.push_alive(op.args[2])) result.append(op) - return result, self.pop_alive(oldval) + result.extend(self.pop_alive(oldval)) + return result def get_rtti(self, TYPE): if isinstance(TYPE, lltype.GcStruct): @@ -425,8 +371,8 @@ def finish(self): super(RefcountingGCTransformer, self).finish() if self.translator and self.translator.rtyper: - for g in self.deallocator_graphs_needing_transforming: - MinimalGCTransformer(self.translator).transform_graph(g) + #for g in self.deallocator_graphs_needing_transforming: + # MinimalGCTransformer(self.translator).transform_graph(g) for g, nsafecalls in self.graphs_needing_exception_cleaning.iteritems(): n = exception_clean(g) assert n == nsafecalls @@ -604,11 +550,11 @@ def replace_gc_protect(self, op, livevars, block): """ for boehm it is enough to do nothing""" - return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] + return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)] def replace_gc_unprotect(self, op, livevars, block): """ for boehm it is enough to do nothing""" - return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)], [] + return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)] def get_rtti(self, TYPE): if isinstance(TYPE, lltype.GcStruct): @@ -623,7 +569,7 @@ for fptr in self.finalizer_funcptrs.itervalues(): if fptr: g = fptr._obj.graph - MinimalGCTransformer(self.translator).transform_graph(g) + #MinimalGCTransformer(self.translator).transform_graph(g) def finalizer_funcptr_for_type(self, TYPE): if TYPE in self.finalizer_funcptrs: @@ -871,8 +817,8 @@ def graph2funcptr(self, graph, attach_empty_cleanup=False): self.seen_graphs[graph] = True - if attach_empty_cleanup: - MinimalGCTransformer(self.translator).transform_graph(graph) + #if attach_empty_cleanup: + # MinimalGCTransformer(self.translator).transform_graph(graph) return const_funcptr_fromgraph(graph) def get_type_id(self, TYPE): Modified: pypy/branch/explicit-exceptions/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/memory/test/test_gctransform.py (original) +++ pypy/branch/explicit-exceptions/rpython/memory/test/test_gctransform.py Wed Mar 22 21:21:38 2006 @@ -2,6 +2,7 @@ from pypy.objspace.flow.model import c_last_exception, Variable from pypy.rpython.memory.gctransform import var_needsgc, var_ispyobj from pypy.translator.translator import TranslationContext, graphof +from pypy.translator.c.exceptiontransform import ExceptionTransformer from pypy.rpython.lltypesystem import lltype from pypy.objspace.flow.model import Variable from pypy.annotation import model as annmodel @@ -59,6 +60,8 @@ def rtype_and_transform(func, inputtypes, transformcls, specialize=True, check=True): t = rtype(func, inputtypes, specialize) + etrafo = ExceptionTransformer(t) + etrafo.transform_completely() transformer = transformcls(t) transformer.transform(t.graphs) if conftest.option.view: @@ -111,7 +114,7 @@ assert False, "direct_call not found!" assert ggraph.startblock.operations[i + 1].opname != 'gc_push_alive' -def test_multiple_exits(): +def DONOTtest_multiple_exits(): S = lltype.GcStruct("S", ('x', lltype.Signed)) T = lltype.GcStruct("T", ('y', lltype.Signed)) def f(n): @@ -147,7 +150,7 @@ passedname = link.target.exits[0].args[0].name assert dyingname != passedname -def test_cleanup_vars_on_call(): +def DONOTtest_cleanup_vars_on_call(): S = lltype.GcStruct("S", ('x', lltype.Signed)) def f(): return lltype.malloc(S) @@ -203,7 +206,7 @@ return s.x t, transformer = rtype_and_transform(g, [], gctransform.GCTransformer) -def test_noconcretetype(): +def DONOTtest_noconcretetype(): def f(): return [1][0] t, transformer = rtype_and_transform(f, [], gctransform.GCTransformer, specialize=False) @@ -243,7 +246,7 @@ ops = getops(graphof(t, f)) assert len(ops.get('direct_call', [])) == ex -def test_protect_unprotect_no_exception_block(): +def DONOTtest_protect_unprotect_no_exception_block(): def p(): protect('this is an object') def u(): unprotect('this is an object') @@ -308,7 +311,7 @@ return c.x t, transformer = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False) ops = getops(graphof(t, f)) - assert len(ops['direct_call']) == 4 + assert ops['direct_call'] >= 4 def test_boehm_simple(): @@ -321,7 +324,7 @@ t, transformer = rtype_and_transform( f, [], gctransform.BoehmGCTransformer, check=False) ops = getops(graphof(t, f)) - assert 'direct_call' not in ops + assert len(ops.get('direct_call', [])) <= 1 gcs = [k for k in ops if k.startswith('gc')] assert len(gcs) == 0 @@ -619,7 +622,7 @@ # ______________________________________________________________________ # tests for FrameworkGCTransformer -def test_framework_simple(): +def DONT_test_framework_simple(): support.AddressLinkedList.unused_chunks = support.FreeList(support.CHUNK_SIZE + 2) # 'leaks' but well def g(x): return x + 1 From arigo at codespeak.net Wed Mar 22 23:17:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 22 Mar 2006 23:17:55 +0100 (CET) Subject: [pypy-svn] r24831 - pypy/dist/pypy/rpython Message-ID: <20060322221755.F0E4310147@code0.codespeak.net> Author: arigo Date: Wed Mar 22 23:17:54 2006 New Revision: 24831 Modified: pypy/dist/pypy/rpython/annlowlevel.py Log: Oups! The intention of not_const() is to avoid modifying the original s_obj. Bug... Modified: pypy/dist/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/dist/pypy/rpython/annlowlevel.py (original) +++ pypy/dist/pypy/rpython/annlowlevel.py Wed Mar 22 23:17:54 2006 @@ -13,7 +13,7 @@ if s_obj.is_constant(): new_s_obj = annmodel.SomeObject() new_s_obj.__class__ = s_obj.__class__ - new_s_obj.__dict__ = s_obj.__dict__ + new_s_obj.__dict__ = s_obj.__dict__.copy() del new_s_obj.const s_obj = new_s_obj return s_obj From cfbolz at codespeak.net Thu Mar 23 00:00:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 23 Mar 2006 00:00:59 +0100 (CET) Subject: [pypy-svn] r24832 - in pypy/branch/explicit-exceptions/translator/c: . src Message-ID: <20060322230059.5C12C10150@code0.codespeak.net> Author: cfbolz Date: Thu Mar 23 00:00:48 2006 New Revision: 24832 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py pypy/branch/explicit-exceptions/translator/c/funcgen.py pypy/branch/explicit-exceptions/translator/c/src/trace.h pypy/branch/explicit-exceptions/translator/c/wrapper.py Log: (cfbolz, mwh, pedronis around): intermediate checkin (breaking more tests, yay!): ripping out exceptions from funcgen. commenting out some set_name calls of doubtful value in wrapper. changing the FAIL macro to do nothing. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 00:00:48 2006 @@ -106,6 +106,7 @@ last_operation -= 1 else: need_exc_matching = False + afterblock = block for i in range(last_operation, -1, -1): op = block.operations[i] print "considering op", op, i @@ -119,10 +120,10 @@ #non-exception case block.exits[0].exitcase = block.exits[0].llexitcase = False if need_exc_matching: - if not self.raise_analyzer.can_raise(op): - print "XXX: operation %s cannot raise, but has exception guarding in graph %s" (op, graph) - block.exitswitch = None - block.exits = [block.exits[0]] + if not self.raise_analyzer.can_raise(block.operations[-1]): + print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (block.operations[-1], graph) + afterblock.exitswitch = None + afterblock.exits = [afterblock.exits[0]] else: self.insert_matching(afterblock, graph) @@ -172,7 +173,7 @@ newop = SpaceOperation(op.opname, opargs, result) startblock = Block(inputargs) startblock.operations.append(newop) - newgraph = FunctionGraph("dummy", startblock) + newgraph = FunctionGraph("dummy_exc1", startblock) startblock.closeblock(Link([result], newgraph.returnblock)) startblock.exits = list(startblock.exits) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype @@ -197,7 +198,7 @@ block.exits[True].target = excblock block.exits[True].args = [] FUNCTYPE = lltype.FuncType(ARGTYPES, op.result.concretetype) - fptr = Constant(lltype.functionptr(FUNCTYPE, "dummy", graph=newgraph), + fptr = Constant(lltype.functionptr(FUNCTYPE, "dummy_exc2", graph=newgraph), lltype.Ptr(FUNCTYPE)) self.translator.graphs.append(newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Thu Mar 23 00:00:48 2006 @@ -57,11 +57,6 @@ for op in block.operations: mix.extend(op.args) mix.append(op.result) - if getattr(op, "cleanup", None) is not None: - cleanup_finally, cleanup_except = op.cleanup - for cleanupop in cleanup_finally + cleanup_except: - mix.extend(cleanupop.args) - mix.append(cleanupop.result) for link in block.exits: mix.extend(link.getextravars()) mix.extend(link.args) @@ -188,31 +183,13 @@ yield '' yield 'block%d:' % myblocknum for i, op in enumerate(block.operations): - err = 'err%d_%d' % (myblocknum, i) - for line in self.gen_op(op, err): + for line in self.gen_op(op, "should_never_be_reached"): yield line - # XXX hackish -- insert the finally code unless the operation - # already did - cleanup = getattr(op, 'cleanup', None) - if (cleanup is not None and - op.opname not in ("direct_call", "indirect_call")): - cleanup_finally, cleanup_except = cleanup - for subop in cleanup_finally: - for line in self.gen_op(subop, "should_never_be_jumped_to2"): - yield line - fallthrough = False if len(block.exits) == 0: - if len(block.inputargs) == 2: # exc_cls, exc_value - # exceptional return block - exc_cls = self.expr(block.inputargs[0]) - exc_value = self.expr(block.inputargs[1]) - yield 'RPyRaiseException(%s, %s);' % (exc_cls, exc_value) - for line in self.return_with_error(): - yield line - else: - # regular return block - retval = self.expr(block.inputargs[0]) - yield 'return %s;' % retval + assert len(block.inputargs) == 1 + # regular return block + retval = self.expr(block.inputargs[0]) + yield 'return %s;' % retval continue elif block.exitswitch is None: # single-exit block @@ -220,48 +197,8 @@ for op in self.gen_link(block.exits[0]): yield op yield '' - elif block.exitswitch == c_last_exception: - # block catching the exceptions raised by its last operation - # we handle the non-exceptional case first - link = block.exits[0] - assert link.exitcase is None - for op in self.gen_link(link): - yield op - # we must catch the exception raised by the last operation, - # which goes to the last err%d_%d label written above. - yield '' - yield 'err%d_%d:' % (myblocknum, len(block.operations) - 1) - yield '' - for link in block.exits[1:]: - assert issubclass(link.exitcase, Exception) - try: - etype = link.llexitcase - except AttributeError: - etype = pyobjectptr(link.exitcase) - T1 = PyObjPtr - T2 = PyObjPtr - else: - assert hasattr(link.last_exception, 'concretetype') - assert hasattr(link.last_exc_value, 'concretetype') - T1 = link.last_exception.concretetype - T2 = link.last_exc_value.concretetype - typ1 = self.db.gettype(T1) - typ2 = self.db.gettype(T2) - yield 'if (RPyMatchException(%s)) {' % (self.db.get(etype),) - yield '\t%s;' % cdecl(typ1, 'exc_cls') - yield '\t%s;' % cdecl(typ2, 'exc_value') - yield '\tRPyFetchException(exc_cls, exc_value, %s);' % ( - cdecl(typ2, '')) - d = {} - if isinstance(link.last_exception, Variable): - d[link.last_exception] = 'exc_cls' - if isinstance(link.last_exc_value, Variable): - d[link.last_exc_value] = 'exc_value' - for op in self.gen_link(link, d): - yield '\t' + op - yield '}' - fallthrough = True else: + assert block.exitswitch != c_last_exception # block ending in a switch on a value TYPE = self.lltypemap(block.exitswitch) if TYPE in (Bool, PyObjPtr): @@ -315,32 +252,6 @@ raise TypeError("exitswitch type not supported" " Got %r" % (TYPE,)) - errorcases = {} - for i, op in list(enumerate(block.operations))[::-1]: - if getattr(op, 'cleanup', None) is None: - continue - cleanup_finally, cleanup_except = op.cleanup - errorcases.setdefault(cleanup_except, []).append(i) - - if fallthrough: - cleanup_finally, firstclean = block.operations[-1].cleanup - first = errorcases[firstclean] - del errorcases[firstclean] - first.remove(len(block.operations) - 1) - items = errorcases.items() - items.insert(0, (firstclean, first)) - else: - items = errorcases.items() - - for cleanupops, labels in items: - for label in labels: - yield 'err%d_%d:' % (myblocknum, label) - for cleanupop in cleanupops: - for line in self.gen_op(cleanupop, 'should_never_be_jumped_to'): - yield line - for line in self.return_with_error(): - yield line - def gen_link(self, link, linklocalvars=None): "Generate the code to jump across the given Link." is_alive = {} @@ -430,21 +341,6 @@ # skip assignment of 'void' return value r = self.expr(op.result) line = '%s = %s' % (r, line) - try: - cleanup = op.cleanup - except AttributeError: - raise AttributeError("%r without explicit .cleanup" - % (op,)) - if cleanup is not None: - # insert the 'finally' operations before the exception check - cleanup_finally, cleanup_except = op.cleanup - if cleanup_finally: - finally_lines = ['/* finally: */'] - for cleanupop in cleanup_finally: - finally_lines.extend( - self.gen_op(cleanupop, 'should_never_be_jumped_to')) - line = '%s\n%s' % (line, '\n\t'.join(finally_lines)) - line = '%s\n%s' % (line, self.check_directcall_result(op, err)) return line # the following works since the extra arguments that indirect_call has Modified: pypy/branch/explicit-exceptions/translator/c/src/trace.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/trace.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/trace.h Thu Mar 23 00:00:48 2006 @@ -32,7 +32,9 @@ #else /* !defined(USE_CALL_TRACE) */ -#define FAIL(err) goto err +/* XXX we need to be more clever when exception handling actually checks for + * specific error values */ +#define FAIL(err) /*goto err */ #endif /* defined(USE_CALL_TRACE) */ Modified: pypy/branch/explicit-exceptions/translator/c/wrapper.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/wrapper.py (original) +++ pypy/branch/explicit-exceptions/translator/c/wrapper.py Thu Mar 23 00:00:48 2006 @@ -69,7 +69,7 @@ vlist.append(Constant(default_value)) v = newops.genop(opname, vlist, resulttype=Ptr(PyObject)) - v.set_name('a', i) + #v.set_name('a', i) varguments.append(v) if vararg: @@ -79,7 +79,7 @@ Constant(None), ] vararg = newops.genop('getslice', vlist, resulttype=Ptr(PyObject)) - vararg.set_name('vararg', 0) + #vararg.set_name('vararg', 0) varguments.append(vararg) else: # "check_no_more_arg(fname, n, vargs)" From cfbolz at codespeak.net Thu Mar 23 00:13:29 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 23 Mar 2006 00:13:29 +0100 (CET) Subject: [pypy-svn] r24833 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060322231329.26EB110151@code0.codespeak.net> Author: cfbolz Date: Thu Mar 23 00:13:28 2006 New Revision: 24833 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: test for bare except Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Thu Mar 23 00:13:28 2006 @@ -109,7 +109,37 @@ result = f(8) assert result == 2 +def test_bare_except(): + def one(x): + if x == 1: + raise ValueError() + elif x == 2: + raise TypeError() + return x - 5 + def foo(x): + x = one(x) + try: + x = one(x) + except: + return 1 + x + return 4 + x + t, g = transform_func(foo, [int]) + assert len(list(g.iterblocks())) == 5 + f = compile_func(foo, [int]) + result = interpret(foo, [6]) + assert result == 2 + result = f(6) + assert result == 2 + result = interpret(foo, [7]) + assert result == 3 + result = f(7) + assert result == 3 + result = interpret(foo, [8]) + assert result == 2 + result = f(8) + assert result == 2 + def test_raises(): def foo(x): if x: From arigo at codespeak.net Thu Mar 23 00:35:10 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 00:35:10 +0100 (CET) Subject: [pypy-svn] r24836 - in pypy/branch/pypy-rdict-refactoring: . annotation rpython rpython/lltypesystem rpython/test Message-ID: <20060322233510.8212A10156@code0.codespeak.net> Author: arigo Date: Thu Mar 23 00:35:06 2006 New Revision: 24836 Added: pypy/branch/pypy-rdict-refactoring/ - copied from r24803, pypy/dist/pypy/ pypy/branch/pypy-rdict-refactoring/rpython/annlowlevel.py - copied unchanged from r24831, pypy/dist/pypy/rpython/annlowlevel.py Modified: pypy/branch/pypy-rdict-refactoring/annotation/model.py pypy/branch/pypy-rdict-refactoring/rpython/llinterp.py pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/rclass.py pypy/branch/pypy-rdict-refactoring/rpython/raddress.py pypy/branch/pypy-rdict-refactoring/rpython/rclass.py pypy/branch/pypy-rdict-refactoring/rpython/rdict.py pypy/branch/pypy-rdict-refactoring/rpython/rfloat.py pypy/branch/pypy-rdict-refactoring/rpython/rint.py pypy/branch/pypy-rdict-refactoring/rpython/rmodel.py pypy/branch/pypy-rdict-refactoring/rpython/rstr.py pypy/branch/pypy-rdict-refactoring/rpython/rtuple.py pypy/branch/pypy-rdict-refactoring/rpython/rtyper.py pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Log: Branch check-in: this rdict refactoring is mostly done, but I got a test_stress failure. (I promize a more detailed log message in the trunk merge.) Modified: pypy/branch/pypy-rdict-refactoring/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/branch/pypy-rdict-refactoring/annotation/model.py Thu Mar 23 00:35:06 2006 @@ -28,7 +28,7 @@ # -from types import BuiltinFunctionType, MethodType +from types import BuiltinFunctionType, MethodType, FunctionType import pypy from pypy.annotation.pairtype import pair, extendabletype from pypy.tool.tls import tlsobject @@ -582,6 +582,11 @@ ll_ptrtype = lltype.typeOf(v.im_self) assert isinstance(ll_ptrtype, lltype.Ptr) return SomeLLADTMeth(ll_ptrtype, v.im_func) + if isinstance(v, FunctionType): + # this case should only be for staticmethod instances used in + # adtmeths: the getattr() result is then a plain FunctionType object. + from pypy.annotation.bookkeeper import getbookkeeper + return getbookkeeper().immutablevalue(v) return lltype_to_annotation(lltype.typeOf(v)) # ____________________________________________________________ Modified: pypy/branch/pypy-rdict-refactoring/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/llinterp.py Thu Mar 23 00:35:06 2006 @@ -449,20 +449,17 @@ def op_getfield(self, obj, field): assert checkptr(obj) - result = getattr(obj, field) # check the difference between op_getfield and op_getsubstruct: - # the former returns the real field, the latter a pointer to it - assert lltype.typeOf(result) == getattr(lltype.typeOf(obj).TO, field) - return result + assert not isinstance(getattr(lltype.typeOf(obj).TO, field), + lltype.ContainerType) + return getattr(obj, field) def op_getsubstruct(self, obj, field): assert checkptr(obj) - result = getattr(obj, field) # check the difference between op_getfield and op_getsubstruct: - # the former returns the real field, the latter a pointer to it - assert (lltype.typeOf(result) == - lltype.Ptr(getattr(lltype.typeOf(obj).TO, field))) - return result + assert isinstance(getattr(lltype.typeOf(obj).TO, field), + lltype.ContainerType) + return getattr(obj, field) def op_getarraysubstruct(self, array, index): assert checkptr(array) Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py Thu Mar 23 00:35:06 2006 @@ -686,9 +686,17 @@ o = getattr(self._obj, field_name) return _expose(o, self._solid) if isinstance(self._T, ContainerType): - adtmeth = self._T._adtmeths.get(field_name) - if adtmeth is not None: - return adtmeth.__get__(self) + try: + adtmeth = self._T._adtmeths[field_name] + except KeyError: + pass + else: + try: + getter = adtmeth.__get__ + except AttributeError: + return adtmeth + else: + return getter(self) raise AttributeError("%r instance has no field %r" % (self._T, field_name)) Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/rclass.py Thu Mar 23 00:35:06 2006 @@ -620,6 +620,8 @@ return obj.typeptr.rtti def ll_inst_hash(ins): + if not ins: + return 0 # for None cached = ins.hash_cache if cached == 0: cached = ins.hash_cache = id(ins) Modified: pypy/branch/pypy-rdict-refactoring/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/raddress.py Thu Mar 23 00:35:06 2006 @@ -44,6 +44,8 @@ def get_ll_hash_function(self): return ll_addrhash + get_ll_fasthash_function = get_ll_hash_function + def ll_addrhash(addr1): return cast_adr_to_int(addr1) Modified: pypy/branch/pypy-rdict-refactoring/rpython/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/rclass.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rclass.py Thu Mar 23 00:35:06 2006 @@ -182,6 +182,9 @@ def get_ll_eq_function(self): return None # defaults to compare by identity ('==' on pointers) + def can_ll_be_null(self, s_value): + return s_value.can_be_none() + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops): Modified: pypy/branch/pypy-rdict-refactoring/rpython/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rdict.py Thu Mar 23 00:35:06 2006 @@ -13,17 +13,15 @@ # generic implementation of RPython dictionary, with parametric DICTKEY and # DICTVALUE types. # -# XXX this should be re-optimized for specific types of keys; e.g. -# for string keys we don't need the two boolean flags but can use -# a NULL and a special 'dummy' keys. Similarily, for immutable dicts, -# the array should be inlined and num_pristine_entries is not needed. +# XXX for immutable dicts, the array should be inlined and +# num_pristine_entries and everused are not needed. # # struct dictentry { # DICTKEY key; -# bool valid; # to mark if the entry is filled -# bool everused; # to mark if the entry is or has ever been filled +# bool f_valid; # (optional) the entry is filled +# bool f_everused; # (optional) the entry is or has ever been filled # DICTVALUE value; -# int hash; +# int f_hash; # (optional) key hash, if hard to recompute # } # # struct dicttable { @@ -61,39 +59,10 @@ def rtyper_makekey(self): return (self.__class__, self.dictdef.dictkey, self.dictdef.dictvalue) -class DictTrait: - # avoid explosion of one helper function per repr - # vs. layout and functions - - def __init__(self, dictrepr): - self.DICT = dictrepr.DICT - self.DICTENTRYARRAY = dictrepr.DICTENTRYARRAY - self.custom_eq_hash = False - self.ll_keyhash = dictrepr.ll_keyhash - self.ll_keyeq = dictrepr.ll_keyeq - - def _freeze_(self): - return True - - def __repr__(self): - return "DictT %s" % self.DICT._short_name() - -def dict_trait(rtyper, dictrepr): - if dictrepr.custom_eq_hash: # in this case use there is not much point in not just using the repr - return dictrepr - - key = (dictrepr.DICT, dictrepr.ll_keyhash, dictrepr.ll_keyeq) - try: - return rtyper._dict_traits[key] - except KeyError: - trait = DictTrait(dictrepr) - rtyper._dict_traits[key] = trait - return trait - class DictRepr(rmodel.Repr): - def __init__(self, rtyper, key_repr, value_repr, dictkey=None, dictvalue=None, + def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, custom_eq_hash=None): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() @@ -113,7 +82,6 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash - self._trait = None # cache for get_trait # setup() needs to be called to finish this initialization def pickrepr(self, item_repr): @@ -142,12 +110,77 @@ if isinstance(self.DICT, lltype.GcForwardReference): self.DICTKEY = self.key_repr.lowleveltype self.DICTVALUE = self.value_repr.lowleveltype - self.DICTENTRY = lltype.Struct("dictentry", - ("key", self.DICTKEY), - ("hash", lltype.Signed), - ("valid", lltype.Bool), - ("everused", lltype.Bool), - ("value", self.DICTVALUE)) + + # compute the shape of the DICTENTRY structure + entryfields = [] + entrymeths = { + 'must_clear_key': (isinstance(self.DICTKEY, lltype.Ptr) + and self.DICTKEY._needsgc()), + 'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr) + and self.DICTVALUE._needsgc()), + } + + # * the key + entryfields.append(("key", self.DICTKEY)) + + # * if NULL is not a valid ll value for the key or the value + # field of the entry, it can be used as a marker for + # never-used entries. Otherwise, we need an explicit flag. + s_key = self.dictkey.s_value + s_value = self.dictvalue.s_value + nullkeymarker = not self.key_repr.can_ll_be_null(s_key) + nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + + if nullkeymarker: + entrymeths['everused'] = ll_everused_from_key + elif nullvaluemarker: + entrymeths['everused'] = ll_everused_from_value + else: + entryfields.append(("f_everused", lltype.Bool)) + entrymeths['everused'] = ll_everused_from_flag + + # * if the key or the value can also contain a "dummy" non-null + # marker, we use it for deleted entries. + rtyper = self.rtyper + dummy_obj = self.key_repr.get_ll_dummyval_obj(rtyper, s_key) + if dummy_obj: + entrymeths['dummy_obj'] = dummy_obj + entrymeths['valid'] = ll_valid_from_key + entrymeths['mark_deleted'] = ll_mark_deleted_in_key + # the key is overwritten by 'dummy' when the entry is deleted + entrymeths['must_clear_key'] = False + else: + dummy_obj = self.value_repr.get_ll_dummyval_obj(rtyper, + s_value) + if dummy_obj: + entrymeths['dummy_obj'] = dummy_obj + entrymeths['valid'] = ll_valid_from_value + entrymeths['mark_deleted'] = ll_mark_deleted_in_value + # value is overwritten by 'dummy' when entry is deleted + entrymeths['must_clear_value'] = False + else: + entryfields.append(("f_valid", lltype.Bool)) + entrymeths['valid'] = ll_valid_from_flag + entrymeths['mark_deleted'] = ll_mark_deleted_in_flag + + # * the value + entryfields.append(("value", self.DICTVALUE)) + + # * the hash, if needed + if self.custom_eq_hash: + fasthashfn = None + else: + fasthashfn = self.key_repr.get_ll_fasthash_function() + if fasthashfn is None: + entryfields.append(("f_hash", lltype.Signed)) + entrymeths['hash'] = ll_hash_from_cache + else: + entrymeths['hash'] = ll_hash_recomputed + entrymeths['fasthashfn'] = fasthashfn + + # Build the lltype data structures + self.DICTENTRY = lltype.Struct("dictentry", adtmeths=entrymeths, + *entryfields) self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY) fields = [ ("num_items", lltype.Signed), ("num_pristine_entries", lltype.Signed), @@ -156,11 +189,25 @@ self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr() fields.extend([ ("fnkeyeq", self.r_rdict_eqfn.lowleveltype), ("fnkeyhash", self.r_rdict_hashfn.lowleveltype) ]) - self.DICT.become(lltype.GcStruct("dicttable", *fields)) - if 'll_keyhash' not in self.__dict__ and not self.custom_eq_hash: - # figure out which functions must be used to hash and compare keys - self.ll_keyeq = self.key_repr.get_ll_eq_function() # can be None - self.ll_keyhash = self.key_repr.get_ll_hash_function() + adtmeths = { + 'keyhash': ll_keyhash_custom, + 'keyeq': ll_keyeq_custom, + 'r_rdict_eqfn': self.r_rdict_eqfn, + 'r_rdict_hashfn': self.r_rdict_hashfn, + } + else: + # figure out which functions must be used to hash and compare + ll_keyhash = self.key_repr.get_ll_hash_function() + ll_keyeq = self.key_repr.get_ll_eq_function() # can be None + ll_keyhash = staticmethod(ll_keyhash) + if ll_keyeq is not None: + ll_keyeq = staticmethod(ll_keyeq) + adtmeths = { + 'keyhash': ll_keyhash, + 'keyeq': ll_keyeq, + } + self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, + *fields)) def recast_value(self, llops, v): return llops.convertvar(v, self.value_repr, self.external_value_repr) @@ -168,11 +215,6 @@ def recast_key(self, llops, v): return llops.convertvar(v, self.key_repr, self.external_key_repr) - def get_trait(self): - if self._trait is None: - self._trait = dict_trait(self.rtyper, self) - return self._trait - def convert_const(self, dictobj): # get object from bound dict methods #dictobj = getattr(dictobj, '__self__', dictobj) @@ -185,7 +227,7 @@ return self.dict_cache[key] except KeyError: self.setup() - l_dict = ll_newdict(self) + l_dict = ll_newdict_size(self.DICT, len(dictobj)) self.dict_cache[key] = l_dict r_key = self.key_repr r_value = self.value_repr @@ -196,38 +238,20 @@ if self.r_rdict_hashfn.lowleveltype != lltype.Void: l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash) l_dict.fnkeyhash = l_fn - # a dummy object with ll_keyeq and ll_keyhash methods to - # pass to ll_dict_setitem() - class Dummy: - custom_eq_hash = False - def ll_keyeq(self, key1, key2): - # theory: all low-level values we consider as keys - # can be compared by equality (i.e. identity for - # pointers) because the r_dict itself should have - # ensured that it does not store duplicate equal keys. - return key1 == key2 - def ll_keyhash(self, key): - # theoretically slow, but well (see theory above) - for llkey, hash in self.cache: - if key == llkey: - return hash - raise TyperError("hash missing in convert_const(%r)" % - (dictobj,)) - dummy = Dummy() - dummy.cache = [] for dictkeycontainer, dictvalue in dictobj._dict.items(): llkey = r_key.convert_const(dictkeycontainer.key) llvalue = r_value.convert_const(dictvalue) - dummy.cache.insert(0, (llkey, dictkeycontainer.hash)) - ll_dict_setitem(l_dict, llkey, llvalue, dummy) + ll_dict_insertclean(l_dict, llkey, llvalue, + dictkeycontainer.hash) return l_dict else: for dictkey, dictvalue in dictobj.items(): llkey = r_key.convert_const(dictkey) llvalue = r_value.convert_const(dictvalue) - ll_dict_setitem(l_dict, llkey, llvalue, self) + ll_dict_insertclean(l_dict, llkey, llvalue, + l_dict.keyhash(llkey)) return l_dict def rtype_len(self, hop): @@ -244,22 +268,19 @@ def rtype_method_get(self, hop): v_dict, v_key, v_default = hop.inputargs(self, self.key_repr, self.value_repr) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default, ctrait) + v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default) return self.recast_value(hop.llops, v_res) def rtype_method_copy(self, hop): v_dict, = hop.inputargs(self) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - return hop.gendirectcall(ll_copy, v_dict, ctrait) + return hop.gendirectcall(ll_copy, v_dict) def rtype_method_update(self, hop): v_dic1, v_dic2 = hop.inputargs(self, self) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - return hop.gendirectcall(ll_update, v_dic1, v_dic2, ctrait) + return hop.gendirectcall(ll_update, v_dic1, v_dic2) def _rtype_method_kvi(self, hop, spec): v_dic, = hop.inputargs(self) @@ -299,28 +320,24 @@ def rtype_getitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key, ctrait) + v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key) return r_dict.recast_value(hop.llops, v_res) def rtype_delitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - return hop.gendirectcall(ll_dict_delitem, v_dict, v_key, ctrait) + return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value, ctrait) + hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value) def rtype_contains((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - return hop.gendirectcall(ll_contains, v_dict, v_key, ctrait) + return hop.gendirectcall(ll_contains, v_dict, v_key) class __extend__(pairtype(DictRepr, DictRepr)): def convert_from_to((r_dict1, r_dict2), v, llops): @@ -342,6 +359,56 @@ # be direct_call'ed from rtyped flow graphs, which means that they will # get flowed and annotated, mostly with SomePtr. +def ll_everused_from_flag(entry): + return entry.f_everused + +def ll_everused_from_key(entry): + return bool(entry.key) + +def ll_everused_from_value(entry): + return bool(entry.value) + +def ll_valid_from_flag(entry): + return entry.f_valid + +def ll_mark_deleted_in_flag(entry): + entry.f_valid = False + +def ll_valid_from_key(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + return entry.everused() and entry.key != dummy + +def ll_mark_deleted_in_key(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + entry.key = dummy + +def ll_valid_from_value(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + return entry.everused() and entry.value != dummy + +def ll_mark_deleted_in_value(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + entry.value = dummy + +def ll_hash_from_cache(entry): + return entry.f_hash + +def ll_hash_recomputed(entry): + ENTRY = lltype.typeOf(entry).TO + return ENTRY.fasthashfn(entry.key) + +def ll_keyhash_custom(d, key): + DICT = lltype.typeOf(d).TO + return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key) + +def ll_keyeq_custom(d, key1, key2): + DICT = lltype.typeOf(d).TO + return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2) + def dum_keys(): pass def dum_values(): pass def dum_items():pass @@ -356,51 +423,69 @@ # check if a dict is True, allowing for None return bool(d) and d.num_items != 0 -def ll_dict_getitem(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - if entry.valid: +def ll_dict_getitem(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + if entry.valid(): return entry.value else: raise KeyError -def ll_dict_setitem(d, key, value, dictrait): - entry = ll_dict_lookup(d, key, dictrait) +def ll_dict_setitem(d, key, value): + hash = d.keyhash(key) + entry = ll_dict_lookup(d, key, hash) + everused = entry.everused() + valid = entry.valid() + # set up the new entry + ENTRY = lltype.typeOf(entry).TO entry.value = value - if entry.valid: + if valid: return - if dictrait.custom_eq_hash: - hash = hlinvoke(dictrait.r_rdict_hashfn, d.fnkeyhash, key) - else: - hash = dictrait.ll_keyhash(key) - entry.key = key - entry.hash = hash - entry.valid = True + entry.key = key + if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash + if hasattr(ENTRY, 'f_valid'): entry.f_valid = True d.num_items += 1 - if not entry.everused: - entry.everused = True + if not everused: + if hasattr(ENTRY, 'f_everused'): entry.f_everused = True d.num_pristine_entries -= 1 if d.num_pristine_entries <= len(d.entries) / 3: - ll_dict_resize(d, dictrait) + ll_dict_resize(d) -def ll_dict_delitem(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - if not entry.valid: +def ll_dict_insertclean(d, key, value, hash): + # Internal routine used by ll_dict_resize() to insert an item which is + # known to be absent from the dict. This routine also assumes that + # the dict contains no deleted entries. This routine has the advantage + # of never calling d.keyhash() and d.keyeq(), so it cannot call back + # to user code. ll_dict_insertclean() doesn't resize the dict, either. + entry = ll_dict_lookup_clean(d, hash) + ENTRY = lltype.typeOf(entry).TO + entry.value = value + entry.key = key + if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash + if hasattr(ENTRY, 'f_valid'): entry.f_valid = True + if hasattr(ENTRY, 'f_everused'): entry.f_everused = True + d.num_items += 1 + d.num_pristine_entries -= 1 + +def ll_dict_delitem(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + if not entry.valid(): raise KeyError - entry.valid = False + entry.mark_deleted() d.num_items -= 1 - # clear the key and the value if they are pointers - keytype = lltype.typeOf(entry).TO.key - if isinstance(keytype, lltype.Ptr): - key = entry.key # careful about destructor side effects - entry.key = lltype.nullptr(keytype.TO) - valuetype = lltype.typeOf(entry).TO.value - if isinstance(valuetype, lltype.Ptr): - entry.value = lltype.nullptr(valuetype.TO) + # clear the key and the value if they are GC pointers + ENTRY = lltype.typeOf(entry).TO + if ENTRY.must_clear_key: + key = entry.key # careful about destructor side effects: + # keep key alive until entry.value has also + # been zeroed (if it must be) + entry.key = lltype.nullptr(ENTRY.key.TO) + if ENTRY.must_clear_value: + entry.value = lltype.nullptr(ENTRY.value.TO) num_entries = len(d.entries) if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4: - ll_dict_resize(d, dictrait) + ll_dict_resize(d) -def ll_dict_resize(d, dictrait): +def ll_dict_resize(d): old_entries = d.entries old_size = len(old_entries) # make a 'new_size' estimate and shrink it if there are many @@ -409,49 +494,41 @@ while new_size > DICT_INITSIZE and d.num_items < new_size / 4: new_size /= 2 d.entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size) - d.num_pristine_entries = new_size - d.num_items + d.num_items = 0 + d.num_pristine_entries = new_size i = 0 while i < old_size: entry = old_entries[i] - if entry.valid: - new_entry = ll_dict_lookup(d, entry.key, dictrait) - new_entry.key = entry.key - new_entry.hash = entry.hash - new_entry.value = entry.value - new_entry.valid = True - new_entry.everused = True + if entry.valid(): + ll_dict_insertclean(d, entry.key, entry.value, entry.hash()) i += 1 # ------- a port of CPython's dictobject.c's lookdict implementation ------- PERTURB_SHIFT = 5 -def ll_dict_lookup(d, key, dictrait): - if dictrait.custom_eq_hash: - hash = hlinvoke(dictrait.r_rdict_hashfn, d.fnkeyhash, key) - else: - hash = dictrait.ll_keyhash(key) +def ll_dict_lookup(d, key, hash): entries = d.entries mask = len(entries) - 1 i = r_uint(hash & mask) # do the first try before any looping entry = entries[i] - if entry.valid: + if entry.valid(): checkingkey = entry.key if checkingkey == key: return entry # found the entry - if entry.hash == hash: - if dictrait.custom_eq_hash: - res = hlinvoke(dictrait.r_rdict_eqfn, d.fnkeyeq, checkingkey, key) + if d.keyeq is not None and entry.hash() == hash: + # correct hash, maybe the key is e.g. a different pointer to + # an equal object + found = d.keyeq(checkingkey, key) + if 1: # XXX not always needed if (entries != d.entries or - not entry.valid or entry.key != checkingkey): + not entry.valid() or entry.key != checkingkey): # the compare did major nasty stuff to the dict: start over - return ll_dict_lookup(d, key, dictrait) - else: - res = dictrait.ll_keyeq is not None and dictrait.ll_keyeq(checkingkey, key) - if res: + return ll_dict_lookup(d, key, hash) + if found: return entry # found the entry freeslot = lltype.nullptr(lltype.typeOf(entry).TO) - elif entry.everused: + elif entry.everused(): freeslot = entry else: return entry # pristine entry -- lookup failed @@ -462,44 +539,65 @@ while 1: i = ((i << 2) + i + perturb + 1) & mask entry = entries[i] - if not entry.everused: + if not entry.everused(): return freeslot or entry - elif entry.valid: + elif entry.valid(): checkingkey = entry.key if checkingkey == key: return entry - if entry.hash == hash: - if dictrait.custom_eq_hash: - res = hlinvoke(dictrait.r_rdict_eqfn, d.fnkeyeq, checkingkey, key) + if d.keyeq is not None and entry.hash() == hash: + # correct hash, maybe the key is e.g. a different pointer to + # an equal object + found = d.keyeq(checkingkey, key) + if 1: # XXX not always needed if (entries != d.entries or - not entry.valid or entry.key != checkingkey): - # the compare did major nasty stuff to the dict: start over - return ll_dict_lookup(d, key, dictrait) - else: - res = dictrait.ll_keyeq is not None and dictrait.ll_keyeq(checkingkey, key) - if res: - return entry + not entry.valid() or entry.key != checkingkey): + # the compare did major nasty stuff to the dict: + # start over + return ll_dict_lookup(d, key, hash) + if found: + return entry # found the entry elif not freeslot: freeslot = entry perturb >>= PERTURB_SHIFT +def ll_dict_lookup_clean(d, hash): + # a simplified version of ll_dict_lookup() which assumes that the + # key is new, and the dictionary doesn't contain deleted entries. + # It only find the next free slot for the given hash. + entries = d.entries + mask = len(entries) - 1 + i = r_uint(hash & mask) + entry = entries[i] + perturb = r_uint(hash) + while entry.everused(): + i = ((i << 2) + i + perturb + 1) & mask + entry = entries[i] + return entry + # ____________________________________________________________ # # Irregular operations. DICT_INITSIZE = 8 -def ll_newdict(dictrait): - d = lltype.malloc(dictrait.DICT) - d.entries = lltype.malloc(dictrait.DICTENTRYARRAY, DICT_INITSIZE) - d.num_items = 0 # but still be explicit +def ll_newdict(DICT): + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE) + #d.num_items = 0 -- defaults d.num_pristine_entries = DICT_INITSIZE return d -def ll_copy_extra_data(targetdict, sourcedict, dictrait): - if dictrait.custom_eq_hash: - targetdict.fnkeyeq = sourcedict.fnkeyeq - targetdict.fnkeyhash = sourcedict.fnkeyhash +def ll_newdict_size(DICT, length_estimate): + length_estimate = (length_estimate // 2) * 3 + n = DICT_INITSIZE + while n < length_estimate: + n *= 2 + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, n) + #d.num_items = 0 -- defaults + d.num_pristine_entries = DICT_INITSIZE + return d def rtype_newdict(hop): hop.inputargs() # no arguments expected @@ -507,8 +605,8 @@ if r_dict == robject.pyobj_repr: # special case: SomeObject: SomeObject dicts! cdict = hop.inputconst(robject.pyobj_repr, dict) return hop.genop('simple_call', [cdict], resulttype = robject.pyobj_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - v_result = hop.gendirectcall(ll_newdict, ctrait) + cDICT = hop.inputconst(lltype.Void, r_dict.DICT) + v_result = hop.gendirectcall(ll_newdict, cDICT) return v_result def rtype_r_dict(hop): @@ -517,9 +615,9 @@ raise TyperError("r_dict() call does not return an r_dict instance") v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, r_dict.r_rdict_hashfn) - ctrait = hop.inputconst(lltype.Void, r_dict) + cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() - v_result = hop.gendirectcall(ll_newdict, ctrait) + v_result = hop.gendirectcall(ll_newdict, cDICT) if r_dict.r_rdict_eqfn.lowleveltype != lltype.Void: cname = hop.inputconst(lltype.Void, 'fnkeyeq') hop.genop('setfield', [v_result, cname, v_eqfn]) @@ -579,7 +677,7 @@ while index < entries_len: entry = entries[index] index = index + 1 - if entry.valid: + if entry.valid(): iter.index = index if func is dum_items: r = lltype.malloc(RETURNTYPE.TO) @@ -597,49 +695,51 @@ # _____________________________________________________________ # methods -def ll_get(dict, key, default, dictrait): - entry = ll_dict_lookup(dict, key, dictrait) - if entry.valid: +def ll_get(dict, key, default): + entry = ll_dict_lookup(dict, key, dict.keyhash(key)) + if entry.valid(): return entry.value else: return default -def ll_copy(dict, dictrait): +def ll_copy(dict): + DICT = lltype.typeOf(dict).TO dictsize = len(dict.entries) - d = lltype.malloc(dictrait.DICT) - d.entries = lltype.malloc(dictrait.DICTENTRYARRAY, dictsize) + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, dictsize) d.num_items = dict.num_items d.num_pristine_entries = dict.num_pristine_entries - ll_copy_extra_data(d, dict, dictrait) + if hasattr(DICT, 'fnkeyeq'): d.fnkeyeq = dict.fnkeyeq + if hasattr(DICT, 'fnkeyhash'): d.fnkeyhash = dict.fnkeyhash i = 0 while i < dictsize: d_entry = d.entries[i] entry = dict.entries[i] + ENTRY = lltype.typeOf(entry).TO d_entry.key = entry.key - d_entry.hash = entry.hash + if hasattr(ENTRY, 'f_valid'): d_entry.f_valid = entry.f_valid + if hasattr(ENTRY, 'f_everused'): d_entry.f_everused = entry.f_everused d_entry.value = entry.value - d_entry.valid = entry.valid - d_entry.everused = entry.everused + if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash i += 1 return d def ll_clear(d): if len(d.entries) == d.num_pristine_entries == DICT_INITSIZE: return - DICTPTR = lltype.typeOf(d) - d.entries = lltype.malloc(DICTPTR.TO.entries.TO, DICT_INITSIZE) + DICT = lltype.typeOf(d).TO + d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE) d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE -def ll_update(dic1, dic2, dictrait): - # XXX warning, no protection against ll_dict_setitem mutating dic2 - d2len = len(dic2.entries) +def ll_update(dic1, dic2): entries = dic2.entries + d2len = len(entries) i = 0 while i < d2len: entry = entries[i] - if entry.valid: - ll_dict_setitem(dic1, entry.key, entry.value, dictrait) + if entry.valid(): + ll_dict_setitem(dic1, entry.key, entry.value) i += 1 # this is an implementation of keys(), values() and items() @@ -655,14 +755,14 @@ def ll_kvi(dic, LIST, func): res = LIST.ll_newlist(dic.num_items) - dlen = len(dic.entries) entries = dic.entries + dlen = len(entries) items = res.ll_items() i = 0 p = 0 while i < dlen: entry = entries[i] - if entry.valid: + if entry.valid(): ELEM = lltype.typeOf(items).TO.OF if func is dum_items: r = lltype.malloc(ELEM.TO) @@ -672,11 +772,11 @@ elif func is dum_keys: items[p] = recast(ELEM, entry.key) elif func is dum_values: - items[p] = recast(ELEM, entry.value) + items[p] = recast(ELEM, entry.value) p += 1 i += 1 return res -def ll_contains(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - return entry.valid +def ll_contains(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + return entry.valid() Modified: pypy/branch/pypy-rdict-refactoring/rpython/rfloat.py ============================================================================== --- pypy/dist/pypy/rpython/rfloat.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rfloat.py Thu Mar 23 00:35:06 2006 @@ -154,8 +154,6 @@ v = (v - float(hipart)) * TAKE_NEXT x = hipart + int(v) + (expo << 15) return x -ll_hash_float.cache_in_dict = True - # # _________________________ Conversions _________________________ Modified: pypy/branch/pypy-rdict-refactoring/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rint.py Thu Mar 23 00:35:06 2006 @@ -225,6 +225,17 @@ def get_ll_hash_function(self): return ll_hash_int + get_ll_fasthash_function = get_ll_hash_function + + def get_ll_dummyval_obj(self, rtyper, s_value): + # if >= 0, then all negative values are special + if s_value.nonneg and not s_value.unsigned: + return signed_repr # whose ll_dummy_value is -1 + else: + return None + + ll_dummy_value = -1 + def rtype_chr(_, hop): vlist = hop.inputargs(Signed) if hop.has_implicit_exception(ValueError): @@ -416,9 +427,11 @@ j += 1 return result -def ll_hash_int(n): +def ll_identity(n): return n +ll_hash_int = ll_identity + def ll_check_chr(n): if 0 <= n <= 255: return Modified: pypy/branch/pypy-rdict-refactoring/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rmodel.py Thu Mar 23 00:35:06 2006 @@ -5,6 +5,7 @@ from pypy.rpython.lltypesystem.lltype import \ Void, Bool, Float, Signed, Char, UniChar, \ typeOf, LowLevelType, Ptr, PyObject, isCompatibleType +from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype from pypy.rpython.error import TyperError, MissingRTypeOperation @@ -135,12 +136,41 @@ def get_ll_hash_function(self): """Return a hash(x) function for low-level values of this Repr. - As a hint, the function can have a flag 'cache_in_dict=True' if it - makes non-trivial computations and its result should be cached in - dictionary entries. """ raise TyperError, 'no hashing function for %r' % self + def get_ll_fasthash_function(self): + """Return a 'fast' hash(x) function for low-level values of this + Repr. The function can assume that 'x' is already stored as a + key in a dict. get_ll_fasthash_function() should return None if + the hash should rather be cached in the dict entry. + """ + return None + + def can_ll_be_null(self, s_value): + """Check if the low-level repr can take the value 0/NULL. + The annotation s_value is provided as a hint because it may + contain more information than the Repr. + """ + return True # conservative + + def get_ll_dummyval_obj(self, rtyper, s_value): + """A dummy value is a special low-level value, not otherwise + used. It should not be the NULL value even if it is special. + This returns either None, or a hashable object that has a + (possibly lazy) attribute 'll_dummy_value'. + The annotation s_value is provided as a hint because it may + contain more information than the Repr. + """ + T = self.lowleveltype + if (isinstance(T, lltype.Ptr) and + isinstance(T.TO, (lltype.Struct, + lltype.Array, + lltype.ForwardReference))): + return DummyValueBuilder(rtyper, T.TO) + else: + return None + def rtype_bltn_list(self, hop): raise TyperError, 'no list() support for %r' % self @@ -310,6 +340,7 @@ lowleveltype = Void def get_ll_eq_function(self): return None def get_ll_hash_function(self): return ll_hash_void + get_ll_fasthash_function = get_ll_hash_function impossible_repr = VoidRepr() # ____________________________________________________________ @@ -390,7 +421,43 @@ return item_repr, rclass.getinstancerepr(rtyper, None) else: return item_repr, item_repr - + + +class DummyValueBuilder(object): + + def __init__(self, rtyper, TYPE): + self.rtyper = rtyper + self.TYPE = TYPE + + def _freeze_(self): + return True + + def __hash__(self): + return hash(self.TYPE) + + def __eq__(self, other): + return (isinstance(other, DummyValueBuilder) and + self.rtyper is other.rtyper and + self.TYPE == other.TYPE) + + def __ne__(self, other): + return not (self == other) + + def build_ll_dummy_value(self): + TYPE = self.TYPE + try: + return self.rtyper.cache_dummy_values[TYPE] + except KeyError: + # generate a dummy ptr to an immortal placeholder struct/array + if TYPE._is_varsize(): + p = lltype.malloc(TYPE, 0, immortal=True) + else: + p = lltype.malloc(TYPE, immortal=True) + self.rtyper.cache_dummy_values[TYPE] = p + return p + + ll_dummy_value = property(build_ll_dummy_value) + # logging/warning Modified: pypy/branch/pypy-rdict-refactoring/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rstr.py Thu Mar 23 00:35:06 2006 @@ -80,6 +80,16 @@ def get_ll_hash_function(self): return ll_strhash + def get_ll_fasthash_function(self): + return ll_strfasthash + + def can_ll_be_null(self, s_value): + if self is string_repr: + return s_value.can_be_none() + else: + return True # for CharRepr/UniCharRepr subclasses, + # where NULL is always valid: it is chr(0) + def rtype_len(_, hop): v_str, = hop.inputargs(string_repr) return hop.gendirectcall(ll_strlen, v_str) @@ -404,6 +414,8 @@ def get_ll_hash_function(self): return ll_char_hash + get_ll_fasthash_function = get_ll_hash_function + def ll_str(self, ch): return ll_chr2str(ch) @@ -476,6 +488,8 @@ def get_ll_hash_function(self): return ll_unichar_hash + get_ll_fasthash_function = get_ll_hash_function + ## def rtype_len(_, hop): ## return hop.inputconst(Signed, 1) ## @@ -641,6 +655,9 @@ s.hash = x return x +def ll_strfasthash(s): + return s.hash # assumes that the hash is already computed + def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) Modified: pypy/branch/pypy-rdict-refactoring/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rtuple.py Thu Mar 23 00:35:06 2006 @@ -81,7 +81,6 @@ source = source % body exec source in miniglobals ll_hash = miniglobals['ll_hash'] - ll_hash.cache_in_dict = True _gen_hash_function_cache[key] = ll_hash return ll_hash @@ -127,6 +126,9 @@ def get_ll_hash_function(self): return gen_hash_function(self.items_r) + def can_ll_be_null(self, s_value): + return False + def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) Modified: pypy/branch/pypy-rdict-refactoring/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rtyper.py Thu Mar 23 00:35:06 2006 @@ -59,6 +59,7 @@ self.concrete_calltables = {} self.class_pbc_attributes = {} self.oo_meth_impls = {} + self.cache_dummy_values = {} self.typererrors = [] self.typererror_count = 0 # make the primitive_to_repr constant mapping Modified: pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Thu Mar 23 00:35:06 2006 @@ -123,7 +123,7 @@ res = interpret(func2, [ord(x), ord(y)]) for i in range(len(res.entries)): - assert not (res.entries[i].everused and not res.entries[i].valid) + assert not (res.entries[i].everused() and not res.entries[i].valid()) def func3(c0, c1, c2, c3, c4, c5, c6, c7): d = {} @@ -143,7 +143,7 @@ for i in range(rdict.DICT_INITSIZE)]) count_frees = 0 for i in range(len(res.entries)): - if not res.entries[i].everused: + if not res.entries[i].everused(): count_frees += 1 assert count_frees >= 3 @@ -444,9 +444,13 @@ yield x def test_stress(): - dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr) + from pypy.annotation.dictdef import DictKey, DictValue + from pypy.annotation import model as annmodel + dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr, + DictKey(None, annmodel.SomeInteger()), + DictValue(None, annmodel.SomeInteger())) dictrepr.setup() - l_dict = rdict.ll_newdict(dictrepr) + l_dict = rdict.ll_newdict(dictrepr.DICT) referencetable = [None] * 400 referencelength = 0 value = 0 @@ -454,7 +458,7 @@ def complete_check(): for n, refvalue in zip(range(len(referencetable)), referencetable): try: - gotvalue = rdict.ll_dict_getitem(l_dict, n, dictrepr) + gotvalue = rdict.ll_dict_getitem(l_dict, n) except KeyError: assert refvalue is None else: @@ -464,18 +468,18 @@ n = int(x*100.0) # 0 <= x < 400 op = repr(x)[-1] if op <= '2' and referencetable[n] is not None: - rdict.ll_dict_delitem(l_dict, n, dictrepr) + rdict.ll_dict_delitem(l_dict, n) referencetable[n] = None referencelength -= 1 elif op <= '6': - rdict.ll_dict_setitem(l_dict, n, value, dictrepr) + rdict.ll_dict_setitem(l_dict, n, value) if referencetable[n] is None: referencelength += 1 referencetable[n] = value value += 1 else: try: - gotvalue = rdict.ll_dict_getitem(l_dict, n, dictrepr) + gotvalue = rdict.ll_dict_getitem(l_dict, n) except KeyError: assert referencetable[n] is None else: @@ -486,6 +490,78 @@ assert l_dict.num_items == referencelength complete_check() +# ____________________________________________________________ + +def test_opt_nullkeymarker(): + def f(): + d = {"hello": None} + d["world"] = None + return "hello" in d, d + res = interpret(f, []) + assert res.item0 == True + DICT = lltype.typeOf(res.item1).TO + assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None string keys + assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strings have a dummy + +def test_opt_nullvaluemarker(): + def f(n): + d = {-5: "abcd"} + d[123] = "def" + return len(d[n]), d + res = interpret(f, [-5]) + assert res.item0 == 4 + DICT = lltype.typeOf(res.item1).TO + assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None str values + assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strs have a dummy + +def test_opt_nonullmarker(): + class A: + pass + def f(n): + if n > 5: + a = A() + else: + a = None + d = {a: -5441} + d[A()] = n+9872 + return d[a], d + res = interpret(f, [-5]) + assert res.item0 == -5441 + DICT = lltype.typeOf(res.item1).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # can-be-None A instances + assert not hasattr(DICT.entries.TO.OF, 'f_valid')# with a dummy A instance + + res = interpret(f, [6]) + assert res.item0 == -5441 + +def test_opt_nonnegint_dummy(): + def f(n): + d = {n: 12} + d[-87] = 24 + del d[n] + return len(d.copy()), d[-87], d + res = interpret(f, [5]) + assert res.item0 == 1 + assert res.item1 == 24 + DICT = lltype.typeOf(res.item2).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero + assert not hasattr(DICT.entries.TO.OF, 'f_valid')# nonneg int: dummy -1 + +def test_opt_no_dummy(): + def f(n): + d = {n: 12} + d[-87] = -24 + del d[n] + return len(d.copy()), d[-87], d + res = interpret(f, [5]) + assert res.item0 == 1 + assert res.item1 == -24 + DICT = lltype.typeOf(res.item2).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero + assert hasattr(DICT.entries.TO.OF, 'f_valid') # no dummy available + +# ____________________________________________________________ + def test_id_instances_keys(): class A: pass @@ -560,4 +636,14 @@ res = interpret(f, [2]) assert res == f(2) - +def test_dict_of_dict(): + def f(n): + d = {} + d[5] = d + d[6] = {} + return len(d[n]) + + res = interpret(f, [5]) + assert res == 2 + res = interpret(f, [6]) + assert res == 0 From mwh at codespeak.net Thu Mar 23 00:52:21 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 00:52:21 +0100 (CET) Subject: [pypy-svn] r24840 - pypy/branch/explicit-exceptions/rpython/memory Message-ID: <20060322235221.B8E8010156@code0.codespeak.net> Author: mwh Date: Thu Mar 23 00:52:20 2006 New Revision: 24840 Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Log: we don't need exception_clean any more. also, remove a few more references to cleanup. Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/memory/gctransform.py (original) +++ pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Thu Mar 23 00:52:20 2006 @@ -203,14 +203,6 @@ if self.translator and self.translator.rtyper: self.mixlevelannotator.finish() -def exception_clean(graph): - c = 0 - for block in graph.iterblocks(): - for op in block.operations: - if op.opname in ('direct_call', 'indirect_call'): - op.cleanup = None - c += 1 - return c class MinimalGCTransformer(GCTransformer): def push_alive_nopyobj(self, var): @@ -272,7 +264,6 @@ def __init__(self, translator): super(RefcountingGCTransformer, self).__init__(translator) self.deallocator_graphs_needing_transforming = [] - self.graphs_needing_exception_cleaning = {} # create incref graph def ll_incref(adr): if adr: @@ -293,7 +284,6 @@ self.decref_ptr = self.inittime_helper( ll_decref, [llmemory.Address, lltype.Ptr(ADDRESS_VOID_FUNC)], lltype.Void) - self.graphs_needing_exception_cleaning[self.decref_ptr.value._obj.graph] = 1 self.no_pointer_dealloc_ptr = self.inittime_helper( ll_no_pointer_dealloc, [llmemory.Address], lltype.Void) # cache graphs: @@ -307,7 +297,7 @@ adr1 = varoftype(llmemory.Address) result = [SpaceOperation("cast_ptr_to_adr", [var], adr1)] result.append(SpaceOperation("direct_call", [self.increfptr, adr1], - varoftype(lltype.Void), cleanup=None)) + varoftype(lltype.Void))) return result def pop_alive_nopyobj(self, var): @@ -321,7 +311,7 @@ result.append(SpaceOperation("direct_call", [self.decref_ptr, adr1, cdealloc_fptr], - varoftype(lltype.Void), cleanup=None)) + varoftype(lltype.Void))) return result def replace_gc_protect(self, op, livevars, block): @@ -370,12 +360,6 @@ def finish(self): super(RefcountingGCTransformer, self).finish() - if self.translator and self.translator.rtyper: - #for g in self.deallocator_graphs_needing_transforming: - # MinimalGCTransformer(self.translator).transform_graph(g) - for g, nsafecalls in self.graphs_needing_exception_cleaning.iteritems(): - n = exception_clean(g) - assert n == nsafecalls def static_deallocation_funcptr_for_type(self, TYPE): if TYPE in self.static_deallocator_funcptrs: @@ -489,7 +473,6 @@ gcheader.signed[0] = 0 llop.gc_call_rtti_destructor(lltype.Void, rtti, addr) g, fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void) - self.graphs_needing_exception_cleaning[g] = 1 self.seen_graphs[g] = True self.dynamic_deallocator_funcptrs[TYPE] = fptr @@ -566,10 +549,6 @@ def finish(self): self.mixlevelannotator.finish() - for fptr in self.finalizer_funcptrs.itervalues(): - if fptr: - g = fptr._obj.graph - #MinimalGCTransformer(self.translator).transform_graph(g) def finalizer_funcptr_for_type(self, TYPE): if TYPE in self.finalizer_funcptrs: @@ -1019,13 +998,13 @@ v = varoftype(llmemory.Address) yield SpaceOperation("cast_ptr_to_adr", [var], v) yield SpaceOperation("direct_call", [self.push_root_ptr, v], - varoftype(lltype.Void), cleanup=None) + varoftype(lltype.Void)) def pop_roots(self, vars): for var in vars[::-1]: v = varoftype(llmemory.Address) yield SpaceOperation("direct_call", [self.pop_root_ptr], - v, cleanup=None) + v) yield SpaceOperation("gc_reload_possibly_moved", [v, var], varoftype(lltype.Void)) From mwh at codespeak.net Thu Mar 23 00:54:18 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 00:54:18 +0100 (CET) Subject: [pypy-svn] r24841 - in pypy/branch/explicit-exceptions/translator/backendopt: . test Message-ID: <20060322235418.3E9F610159@code0.codespeak.net> Author: mwh Date: Thu Mar 23 00:54:16 2006 New Revision: 24841 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py pypy/branch/explicit-exceptions/translator/backendopt/test/test_inline.py Log: inline doesn't have to care about cleanups any more either. Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 00:54:16 2006 @@ -126,6 +126,7 @@ count = 0 non_recursive = {} while self.block_to_index: + print '!!!', self.block_to_index block, d = self.block_to_index.popitem() index_operation, subgraph = d.popitem() if d: @@ -135,10 +136,6 @@ else: non_recursive[subgraph] = True operation = block.operations[index_operation] - if getattr(operation, "cleanup", None) is not None: - finallyops, exceptops = operation.cleanup - if finallyops or exceptops: - raise CannotInline("cannot inline a function with cleanup attached") self.inline_once(block, index_operation) count += 1 self.cleanup() @@ -147,7 +144,6 @@ def inline_once(self, block, index_operation): self.varmap = {} self._copied_blocks = {} - self._copied_cleanups = {} self.op = block.operations[index_operation] self.graph_to_inline = self.op.args[0].value._obj.graph self.exception_guarded = False @@ -203,26 +199,8 @@ def copy_operation(self, op): args = [self.get_new_name(arg) for arg in op.args] result = SpaceOperation(op.opname, args, self.get_new_name(op.result)) - if getattr(op, "cleanup", None) is not None: - result.cleanup = self.copy_cleanup(op.cleanup) return result - def copy_cleanup(self, cleanup): - if cleanup is None: - return None - if cleanup in self._copied_cleanups: - return self._copied_cleanups[cleanup] - finallyops, exceptops = cleanup - copyfinallyops = [] - for op in finallyops: - copyfinallyops.append(self.copy_operation(op)) - copyexceptops = [] - for op in exceptops: - copyexceptops.append(self.copy_operation(op)) - copycleanup = (tuple(copyfinallyops), tuple(copyexceptops)) - self._copied_cleanups[cleanup] = copycleanup - return copycleanup - def copy_block(self, block): if block in self._copied_blocks: return self._copied_blocks[block] @@ -407,6 +385,7 @@ linktoinlined.target = copiedstartblock linktoinlined.args = passon_args afterblock.inputargs = [self.op.result] + afterblock.inputargs + print '@@@@', (block.operations, afterblock.operations) afterblock.operations = self.generate_keepalive(afterblock.inputargs) + afterblock.operations[1:] if self.graph_to_inline.returnblock in self.entrymap: self.rewire_returnblock(afterblock) Modified: pypy/branch/explicit-exceptions/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/test/test_inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/test/test_inline.py Thu Mar 23 00:54:16 2006 @@ -427,46 +427,3 @@ return 1 assert x4() == 1 py.test.raises(CannotInline, check_inline, x3, x4, []) - -def test_dont_inline_with_cleanups(): - from pypy.objspace.flow.model import Variable, SpaceOperation, Constant - from pypy.rpython.lltypesystem.lltype import Signed - import math - def f(x): - return math.sqrt(x) - def g(x): - return f(x) - t = translate(g, [int]) - graph = graphof(t, f) - ggraph = graphof(t, g) - xvar = ggraph.startblock.inputargs[0] - result = Variable() - result.concretetype = Signed - cleanupop = SpaceOperation("int_add", [Constant(1, Signed), xvar], result) - cleanup = ((cleanupop, ), (cleanupop, )) - ggraph.startblock.operations[0].cleanup = cleanup - py.test.raises(CannotInline, inline_function, t, f, ggraph) - -def test_inline_copies_cleanups(): - from pypy.objspace.flow.model import Variable, SpaceOperation, Constant - from pypy.rpython.lltypesystem.lltype import Signed - import math - def f(x): - return math.sqrt(x) - def g(x): - return f(x) - t = translate(g, [int]) - graph = graphof(t, f) - ggraph = graphof(t, g) - xvar = graph.startblock.inputargs[0] - result = Variable() - result.concretetype = Signed - cleanupop = SpaceOperation("int_add", [Constant(1, Signed), xvar], result) - cleanup = ((cleanupop, ), (cleanupop, )) - graph.startblock.operations[0].cleanup = cleanup - inline_function(t, f, ggraph) - if option.view: - t.view() - assert hasattr(ggraph.startblock.operations[0], "cleanup") - - From mwh at codespeak.net Thu Mar 23 01:00:21 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:00:21 +0100 (CET) Subject: [pypy-svn] r24842 - pypy/branch/explicit-exceptions/rpython/memory Message-ID: <20060323000021.3CF6910155@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:00:09 2006 New Revision: 24842 Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Log: more cleanup related cruft dies. Modified: pypy/branch/explicit-exceptions/rpython/memory/gctransform.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/memory/gctransform.py (original) +++ pypy/branch/explicit-exceptions/rpython/memory/gctransform.py Thu Mar 23 01:00:09 2006 @@ -437,10 +437,6 @@ g, fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void) # the produced deallocator graph does not need to be transformed self.seen_graphs[g] = True - if destrptr: - # however, the direct_call to the destructor needs to get - # .cleanup attached - self.deallocator_graphs_needing_transforming.append(g) self.static_deallocator_funcptrs[TYPE] = fptr for p in find_gc_ptrs_in_type(TYPE): @@ -784,20 +780,17 @@ [s_gcdata] + [annmodel.SomeInteger(nonneg=True) for i in range(5)], annmodel.SomeAddress()) annhelper.finish() # at this point, annotate all mix-level helpers - self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph, - attach_empty_cleanup=True) + self.frameworkgc_setup_ptr = self.graph2funcptr(frameworkgc_setup_graph) self.push_root_ptr = self.graph2funcptr(push_root_graph) self.graphs_to_inline[push_root_graph] = True self.pop_root_ptr = self.graph2funcptr(pop_root_graph) self.graphs_to_inline[pop_root_graph] = True - self.malloc_fixedsize_ptr = self.graph2funcptr(malloc_fixedsize_graph, True) - self.malloc_varsize_ptr = self.graph2funcptr(malloc_varsize_graph, True) + self.malloc_fixedsize_ptr = self.graph2funcptr(malloc_fixedsize_graph) + self.malloc_varsize_ptr = self.graph2funcptr(malloc_varsize_graph) self.graphs_to_inline[malloc_fixedsize_graph] = True - def graph2funcptr(self, graph, attach_empty_cleanup=False): + def graph2funcptr(self, graph): self.seen_graphs[graph] = True - #if attach_empty_cleanup: - # MinimalGCTransformer(self.translator).transform_graph(graph) return const_funcptr_fromgraph(graph) def get_type_id(self, TYPE): From mwh at codespeak.net Thu Mar 23 01:00:47 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:00:47 +0100 (CET) Subject: [pypy-svn] r24843 - pypy/branch/explicit-exceptions/translator/backendopt Message-ID: <20060323000047.52E7E1015C@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:00:46 2006 New Revision: 24843 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py Log: oops, didn't mean to check this in Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 01:00:46 2006 @@ -385,7 +385,6 @@ linktoinlined.target = copiedstartblock linktoinlined.args = passon_args afterblock.inputargs = [self.op.result] + afterblock.inputargs - print '@@@@', (block.operations, afterblock.operations) afterblock.operations = self.generate_keepalive(afterblock.inputargs) + afterblock.operations[1:] if self.graph_to_inline.returnblock in self.entrymap: self.rewire_returnblock(afterblock) From mwh at codespeak.net Thu Mar 23 01:04:38 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:04:38 +0100 (CET) Subject: [pypy-svn] r24844 - pypy/branch/explicit-exceptions/objspace/flow Message-ID: <20060323000438.E424A10156@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:04:32 2006 New Revision: 24844 Modified: pypy/branch/explicit-exceptions/objspace/flow/model.py Log: remove cleanup from SpaceOperation.__slots__ and a few other references. Modified: pypy/branch/explicit-exceptions/objspace/flow/model.py ============================================================================== --- pypy/branch/explicit-exceptions/objspace/flow/model.py (original) +++ pypy/branch/explicit-exceptions/objspace/flow/model.py Thu Mar 23 01:04:32 2006 @@ -192,14 +192,10 @@ return txt def reallyalloperations(self): - "Iterate over all operations, including cleanup sub-operations." + """Iterate over all operations, including cleanup sub-operations. + XXX remove!""" for op in self.operations: yield op - cleanup = getattr(op, 'cleanup', None) - if cleanup is not None: - for lst in cleanup: - for subop in lst: - yield subop def getvariables(self): "Return all variables mentioned in this Block." @@ -333,21 +329,14 @@ __reduce__ = __reduce_ex__ -NOCLEANUP = object() - class SpaceOperation(object): - __slots__ = "opname args result offset cleanup".split() + __slots__ = "opname args result offset".split() - def __init__(self, opname, args, result, offset=-1, cleanup=NOCLEANUP): + def __init__(self, opname, args, result, offset=-1): self.opname = intern(opname) # operation name self.args = list(args) # mixed list of var/const self.result = result # either Variable or Constant instance self.offset = offset # offset in code string - if cleanup is not NOCLEANUP: - # None or a pair of tuples of operations: - # 0. operations to perform in all cases after 'self' - # 1. more operations to perform only in case of exception - self.cleanup = cleanup def __eq__(self, other): return (self.__class__ is other.__class__ and @@ -362,17 +351,8 @@ return hash((self.opname,tuple(self.args),self.result)) def __repr__(self): - s = "%r = %s(%s)" % (self.result, self.opname, ", ".join(map(repr, self.args))) - cleanup = getattr(self, 'cleanup', None) - if cleanup is not None: - lines = [s] - for case, lst in zip((" finally: ", " except: "), cleanup): - indent = case - for subop in lst: - lines.append(indent + repr(subop)) - indent = ' ' * len(indent) - s = '\n'.join(lines) - return s + return "%r = %s(%s)" % (self.result, self.opname, + ", ".join(map(repr, self.args))) def __reduce_ex__(self, *args): # avoid lots of useless list entities @@ -523,8 +503,6 @@ [copyvar(v) for v in op.args], copyvar(op.result)) copyop.offset = op.offset - if hasattr(op, 'cleanup'): - copyop.cleanup = copyoplist(op.cleanup) result.append(copyop) return result newblock.operations = copyoplist(block.operations) From mwh at codespeak.net Thu Mar 23 01:42:43 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:42:43 +0100 (CET) Subject: [pypy-svn] r24845 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323004243.7562510155@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:42:38 2006 New Revision: 24845 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: one simplification: gen_exc_checking_var only used half its arguments and its return value was never used, so tidy there. also, one probable fix, and an assert, about where the exception-guarded operation has ended up. still not convinced this is right. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 01:42:38 2006 @@ -115,13 +115,14 @@ afterblock = split_block(self.translator, graph, block, i+1) - var_exc_occured, block = self.gen_exc_checking_var(op, i, block, graph) + self.gen_exc_check(block, graph.returnblock) #non-exception case block.exits[0].exitcase = block.exits[0].llexitcase = False if need_exc_matching: - if not self.raise_analyzer.can_raise(block.operations[-1]): - print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (block.operations[-1], graph) + assert afterblock.exitswitch == c_last_exception + if not self.raise_analyzer.can_raise(afterblock.operations[-1]): + print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (afterblock.operations[-1], graph) afterblock.exitswitch = None afterblock.exits = [afterblock.exits[0]] else: @@ -177,7 +178,7 @@ startblock.closeblock(Link([result], newgraph.returnblock)) startblock.exits = list(startblock.exits) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype - var_exc_occured, block = self.gen_exc_checking_var(newop, 0, startblock, newgraph) + self.gen_exc_check(startblock, newgraph.returnblock) startblock.exits[0].exitcase = startblock.exits[0].llexitcase = False excblock = Block([]) var_value = Variable() @@ -195,25 +196,24 @@ newgraph.exceptblock.inputargs[0].concretetype = self.exc_data.lltype_of_exception_type newgraph.exceptblock.inputargs[1].concretetype = self.exc_data.lltype_of_exception_value excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) - block.exits[True].target = excblock - block.exits[True].args = [] + startblock.exits[True].target = excblock + startblock.exits[True].args = [] FUNCTYPE = lltype.FuncType(ARGTYPES, op.result.concretetype) fptr = Constant(lltype.functionptr(FUNCTYPE, "dummy_exc2", graph=newgraph), lltype.Ptr(FUNCTYPE)) self.translator.graphs.append(newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) - def gen_exc_checking_var(self, op, i, block, graph): + def gen_exc_check(self, block, returnblock): var_exc_occured = Variable() var_exc_occured.concretetype = lltype.Bool block.operations.append(SpaceOperation("direct_call", [self.rpyexc_occured_ptr], var_exc_occured)) block.exitswitch = var_exc_occured #exception occurred case - l = Link([error_value(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) + l = Link([error_value(returnblock.inputargs[0].concretetype)], returnblock) l.prevblock = block l.exitcase = l.llexitcase = True block.exits.append(l) - return var_exc_occured, block From mwh at codespeak.net Thu Mar 23 01:53:04 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:53:04 +0100 (CET) Subject: [pypy-svn] r24846 - pypy/branch/explicit-exceptions/translator/backendopt Message-ID: <20060323005304.0F62410155@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:52:59 2006 New Revision: 24846 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py Log: oops, another print slipped in Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 01:52:59 2006 @@ -126,7 +126,6 @@ count = 0 non_recursive = {} while self.block_to_index: - print '!!!', self.block_to_index block, d = self.block_to_index.popitem() index_operation, subgraph = d.popitem() if d: From mwh at codespeak.net Thu Mar 23 01:54:30 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 01:54:30 +0100 (CET) Subject: [pypy-svn] r24847 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323005430.483A710155@code0.codespeak.net> Author: mwh Date: Thu Mar 23 01:54:27 2006 New Revision: 24847 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: assert that the call to inline_all() found something to inline. unfortunately, it does, and yet the inlining still doesn't work :( Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 01:54:27 2006 @@ -147,7 +147,8 @@ block.exits[0].exitcase = block.exits[0].llexitcase = None # use the dangerous second True flag :-) inliner = inline.Inliner(self.translator, graph, proxygraph, True, True) - inliner.inline_all() + count = inliner.inline_all() + assert count > 0, "didn't inline" block.exits[0].exitcase = block.exits[0].llexitcase = False def create_proxy_graph(self, op): From mwh at codespeak.net Thu Mar 23 02:10:11 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 02:10:11 +0100 (CET) Subject: [pypy-svn] r24849 - pypy/branch/explicit-exceptions/translator/backendopt Message-ID: <20060323011011.8C56410156@code0.codespeak.net> Author: mwh Date: Thu Mar 23 02:10:03 2006 New Revision: 24849 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py Log: call join_blocks *before* we find the callsites -- otherwise we risk finding callsites in blocks that will soon not be part of the graph. (too late at night and too painful to write a test case, sorry). Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 02:10:03 2006 @@ -107,9 +107,10 @@ self.translator = translator self.graph = graph self.inline_func = inline_func - callsites = find_callsites(graph, inline_func) # to simplify exception matching join_blocks(graph) + # find callsites *after* joining blocks... + callsites = find_callsites(graph, inline_func) self.block_to_index = {} for g, block, i in callsites: self.block_to_index.setdefault(block, {})[i] = g From mwh at codespeak.net Thu Mar 23 02:11:13 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 02:11:13 +0100 (CET) Subject: [pypy-svn] r24850 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323011113.8ECA010158@code0.codespeak.net> Author: mwh Date: Thu Mar 23 02:11:12 2006 New Revision: 24850 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: try harder to hang on the block with the guarded operation (if any) in it. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 02:11:12 2006 @@ -106,7 +106,7 @@ last_operation -= 1 else: need_exc_matching = False - afterblock = block + lastblock = block for i in range(last_operation, -1, -1): op = block.operations[i] print "considering op", op, i @@ -114,19 +114,21 @@ continue afterblock = split_block(self.translator, graph, block, i+1) + if lastblock is block: + lastblock = afterblock self.gen_exc_check(block, graph.returnblock) #non-exception case block.exits[0].exitcase = block.exits[0].llexitcase = False if need_exc_matching: - assert afterblock.exitswitch == c_last_exception - if not self.raise_analyzer.can_raise(afterblock.operations[-1]): - print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (afterblock.operations[-1], graph) - afterblock.exitswitch = None - afterblock.exits = [afterblock.exits[0]] + assert lastblock.exitswitch == c_last_exception + if 0 and not self.raise_analyzer.can_raise(lastblock.operations[-1]): + print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (lastblock.operations[-1], graph) + lastblock.exitswitch = None + lastblock.exits = [lastblock.exits[0]] else: - self.insert_matching(afterblock, graph) + self.insert_matching(lastblock, graph) def transform_except_block(self, graph, block): # attach an except block -- let's hope that nobody uses it From arigo at codespeak.net Thu Mar 23 09:36:42 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 09:36:42 +0100 (CET) Subject: [pypy-svn] r24862 - pypy/branch/pypy-rdict-refactoring/rpython Message-ID: <20060323083642.260EC10151@code0.codespeak.net> Author: arigo Date: Thu Mar 23 09:36:31 2006 New Revision: 24862 Modified: pypy/branch/pypy-rdict-refactoring/rpython/rdict.py Log: Found the bug in the dict code, detected by test_stress. Modified: pypy/branch/pypy-rdict-refactoring/rpython/rdict.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rdict.py Thu Mar 23 09:36:31 2006 @@ -573,6 +573,7 @@ while entry.everused(): i = ((i << 2) + i + perturb + 1) & mask entry = entries[i] + perturb >>= PERTURB_SHIFT return entry # ____________________________________________________________ From arigo at codespeak.net Thu Mar 23 11:07:30 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 11:07:30 +0100 (CET) Subject: [pypy-svn] r24866 - pypy/branch/pypy-rdict-refactoring/rpython/test Message-ID: <20060323100730.578AB1012D@code0.codespeak.net> Author: arigo Date: Thu Mar 23 11:07:24 2006 New Revision: 24866 Modified: pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Log: Print the seed used, to allow reproducing a failure. Modified: pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Thu Mar 23 11:07:24 2006 @@ -437,6 +437,7 @@ Could be useful to detect problems associated with specific usage patterns.""" import random x = random.random() + print 'random seed: %r' % (x,) for i in range(12000): r = 3.4 + i/20000.0 x = r*x - x*x From arigo at codespeak.net Thu Mar 23 11:09:59 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 11:09:59 +0100 (CET) Subject: [pypy-svn] r24867 - in pypy/branch/pypy-rdict-refactoring/rpython: . lltypesystem Message-ID: <20060323100959.2B60D1012D@code0.codespeak.net> Author: arigo Date: Thu Mar 23 11:09:57 2006 New Revision: 24867 Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py pypy/branch/pypy-rdict-refactoring/rpython/rdict.py Log: Argh! staticmethod() is hashed by identity in CPython. Bad surprize. Need a custom version... Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py Thu Mar 23 11:09:57 2006 @@ -1128,6 +1128,31 @@ func._type_method = True return func +class staticAdtMethod(object): + # Like staticmethod(), but for ADT methods. The difference is only + # that this version compares and hashes correctly, unlike CPython's. + def __init__(self, obj): + self.obj = obj + + def __get__(self, inst, typ=None): + return self.obj + + def __hash__(self): + return hash(self.obj) + + def __eq__(self, other): + if not isinstance(other, staticMethod): + return NotImplemented + else: + return self.obj == other.obj + + def __ne__(self, other): + if not isinstance(other, staticMethod): + return NotImplemented + else: + return self.obj != other.obj + + def dissect_ll_instance(v, t=None, memo=None): if memo is None: memo = {} Modified: pypy/branch/pypy-rdict-refactoring/rpython/rdict.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/rdict.py Thu Mar 23 11:09:57 2006 @@ -199,9 +199,9 @@ # figure out which functions must be used to hash and compare ll_keyhash = self.key_repr.get_ll_hash_function() ll_keyeq = self.key_repr.get_ll_eq_function() # can be None - ll_keyhash = staticmethod(ll_keyhash) + ll_keyhash = lltype.staticAdtMethod(ll_keyhash) if ll_keyeq is not None: - ll_keyeq = staticmethod(ll_keyeq) + ll_keyeq = lltype.staticAdtMethod(ll_keyeq) adtmeths = { 'keyhash': ll_keyhash, 'keyeq': ll_keyeq, From arigo at codespeak.net Thu Mar 23 11:30:58 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 11:30:58 +0100 (CET) Subject: [pypy-svn] r24868 - in pypy/branch/pypy-rdict-refactoring/rpython: lltypesystem test Message-ID: <20060323103058.D4FDA10137@code0.codespeak.net> Author: arigo Date: Thu Mar 23 11:30:47 2006 New Revision: 24868 Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Log: Typo (thanks Ben Young). Quite hard to test because CPython eats all exceptions in __eq__ called by the dict lookup algorithm! Bad CPython! Modified: pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/lltypesystem/lltype.py Thu Mar 23 11:30:47 2006 @@ -1141,13 +1141,13 @@ return hash(self.obj) def __eq__(self, other): - if not isinstance(other, staticMethod): + if not isinstance(other, staticAdtMethod): return NotImplemented else: return self.obj == other.obj def __ne__(self, other): - if not isinstance(other, staticMethod): + if not isinstance(other, staticAdtMethod): return NotImplemented else: return self.obj != other.obj Modified: pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py ============================================================================== --- pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py (original) +++ pypy/branch/pypy-rdict-refactoring/rpython/test/test_rdict.py Thu Mar 23 11:30:47 2006 @@ -561,6 +561,22 @@ assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero assert hasattr(DICT.entries.TO.OF, 'f_valid') # no dummy available +def test_opt_multiple_identical_dicts(): + def f(n): + s = "x" * n + d1 = {s: 12} + d2 = {s: 24} + d3 = {s: 36} + d1["a"] = d2[s] # 24 + d3[s] += d1["a"] # 60 + d2["bc"] = d3[s] # 60 + return d2["bc"], d1, d2, d3 + res = interpret(f, [5]) + assert res.item0 == 60 + # all three dicts should use the same low-level type + assert lltype.typeOf(res.item1) == lltype.typeOf(res.item2) + assert lltype.typeOf(res.item1) == lltype.typeOf(res.item3) + # ____________________________________________________________ def test_id_instances_keys(): From arigo at codespeak.net Thu Mar 23 13:24:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 13:24:50 +0100 (CET) Subject: [pypy-svn] r24877 - in pypy: branch/pypy-rdict-refactoring dist/pypy/annotation dist/pypy/rpython dist/pypy/rpython/lltypesystem dist/pypy/rpython/test Message-ID: <20060323122450.B079510142@code0.codespeak.net> Author: arigo Date: Thu Mar 23 13:24:40 2006 New Revision: 24877 Removed: pypy/branch/pypy-rdict-refactoring/ Modified: pypy/dist/pypy/annotation/model.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/raddress.py pypy/dist/pypy/rpython/rclass.py pypy/dist/pypy/rpython/rdict.py pypy/dist/pypy/rpython/rfloat.py pypy/dist/pypy/rpython/rint.py pypy/dist/pypy/rpython/rmodel.py pypy/dist/pypy/rpython/rstr.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/rtyper.py pypy/dist/pypy/rpython/test/test_rdict.py Log: Merge of the branch/pypy-rdict-refactoring: improve rdict.py for more compact hash tables. * Dict entries are more compact: the fields 'valid', 'everused' and 'hash' have been made optional and renamed. * Manipulating dicts from ll helpers is more natural now, by using ADT methods on the dict itself or on the entries. DictTrait is gone. Relies now on the inliner to remove the overhead of all these tiny ADT methods * Added ll_dict_insertclean(), which works like ll_dict_setitem() but for keys known to be new. Useful to initialize prebuilt instances, or to resize more efficiently. * Reprs have a few extra methods (with conservative defaults) to know if the NULL low-level value is used or not by the Repr, and if there are other non-NULL low-level values that are unused (called "dummy"). * For Ptr-to-Struct and Ptr-to-Array low-level types there is always a possible dummy: a pointer to an immortal not-otherwise-used structure. Note that ll_dummy_value is a lazily computed attribute in class Repr, because it is not possible to malloc the dummy immortal before the structure is setup(). * In general, a lot of fun pushing the ADT methods to their limits. Various non-method objects are stored in the ADT of the entries. These objects hash and compare equal as often as possible to avoid duplication of helpers in the final code. * Bug fix: hash() of a NULL instance segfaulted. * Bug fix: 'getfield' in llinterp was not too happy with Void results not actually returning None. Result: pypy-c now contains 24 versions of dictionaries instead of 19. The difference comes from similar versions with or without some flags. E.g. it seems that we have a few dicts using string-or-none as keys, while most use strings-that-cannot-be-none. Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Thu Mar 23 13:24:40 2006 @@ -28,7 +28,7 @@ # -from types import BuiltinFunctionType, MethodType +from types import BuiltinFunctionType, MethodType, FunctionType import pypy from pypy.annotation.pairtype import pair, extendabletype from pypy.tool.tls import tlsobject @@ -582,6 +582,11 @@ ll_ptrtype = lltype.typeOf(v.im_self) assert isinstance(ll_ptrtype, lltype.Ptr) return SomeLLADTMeth(ll_ptrtype, v.im_func) + if isinstance(v, FunctionType): + # this case should only be for staticmethod instances used in + # adtmeths: the getattr() result is then a plain FunctionType object. + from pypy.annotation.bookkeeper import getbookkeeper + return getbookkeeper().immutablevalue(v) return lltype_to_annotation(lltype.typeOf(v)) # ____________________________________________________________ Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Thu Mar 23 13:24:40 2006 @@ -449,20 +449,17 @@ def op_getfield(self, obj, field): assert checkptr(obj) - result = getattr(obj, field) # check the difference between op_getfield and op_getsubstruct: - # the former returns the real field, the latter a pointer to it - assert lltype.typeOf(result) == getattr(lltype.typeOf(obj).TO, field) - return result + assert not isinstance(getattr(lltype.typeOf(obj).TO, field), + lltype.ContainerType) + return getattr(obj, field) def op_getsubstruct(self, obj, field): assert checkptr(obj) - result = getattr(obj, field) # check the difference between op_getfield and op_getsubstruct: - # the former returns the real field, the latter a pointer to it - assert (lltype.typeOf(result) == - lltype.Ptr(getattr(lltype.typeOf(obj).TO, field))) - return result + assert isinstance(getattr(lltype.typeOf(obj).TO, field), + lltype.ContainerType) + return getattr(obj, field) def op_getarraysubstruct(self, array, index): assert checkptr(array) Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Thu Mar 23 13:24:40 2006 @@ -686,9 +686,17 @@ o = getattr(self._obj, field_name) return _expose(o, self._solid) if isinstance(self._T, ContainerType): - adtmeth = self._T._adtmeths.get(field_name) - if adtmeth is not None: - return adtmeth.__get__(self) + try: + adtmeth = self._T._adtmeths[field_name] + except KeyError: + pass + else: + try: + getter = adtmeth.__get__ + except AttributeError: + return adtmeth + else: + return getter(self) raise AttributeError("%r instance has no field %r" % (self._T, field_name)) @@ -1120,6 +1128,31 @@ func._type_method = True return func +class staticAdtMethod(object): + # Like staticmethod(), but for ADT methods. The difference is only + # that this version compares and hashes correctly, unlike CPython's. + def __init__(self, obj): + self.obj = obj + + def __get__(self, inst, typ=None): + return self.obj + + def __hash__(self): + return hash(self.obj) + + def __eq__(self, other): + if not isinstance(other, staticAdtMethod): + return NotImplemented + else: + return self.obj == other.obj + + def __ne__(self, other): + if not isinstance(other, staticAdtMethod): + return NotImplemented + else: + return self.obj != other.obj + + def dissect_ll_instance(v, t=None, memo=None): if memo is None: memo = {} Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Thu Mar 23 13:24:40 2006 @@ -620,6 +620,8 @@ return obj.typeptr.rtti def ll_inst_hash(ins): + if not ins: + return 0 # for None cached = ins.hash_cache if cached == 0: cached = ins.hash_cache = id(ins) Modified: pypy/dist/pypy/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/dist/pypy/rpython/raddress.py Thu Mar 23 13:24:40 2006 @@ -44,6 +44,8 @@ def get_ll_hash_function(self): return ll_addrhash + get_ll_fasthash_function = get_ll_hash_function + def ll_addrhash(addr1): return cast_adr_to_int(addr1) Modified: pypy/dist/pypy/rpython/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/rclass.py (original) +++ pypy/dist/pypy/rpython/rclass.py Thu Mar 23 13:24:40 2006 @@ -182,6 +182,9 @@ def get_ll_eq_function(self): return None # defaults to compare by identity ('==' on pointers) + def can_ll_be_null(self, s_value): + return s_value.can_be_none() + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops): Modified: pypy/dist/pypy/rpython/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/rdict.py (original) +++ pypy/dist/pypy/rpython/rdict.py Thu Mar 23 13:24:40 2006 @@ -13,17 +13,15 @@ # generic implementation of RPython dictionary, with parametric DICTKEY and # DICTVALUE types. # -# XXX this should be re-optimized for specific types of keys; e.g. -# for string keys we don't need the two boolean flags but can use -# a NULL and a special 'dummy' keys. Similarily, for immutable dicts, -# the array should be inlined and num_pristine_entries is not needed. +# XXX for immutable dicts, the array should be inlined and +# num_pristine_entries and everused are not needed. # # struct dictentry { # DICTKEY key; -# bool valid; # to mark if the entry is filled -# bool everused; # to mark if the entry is or has ever been filled +# bool f_valid; # (optional) the entry is filled +# bool f_everused; # (optional) the entry is or has ever been filled # DICTVALUE value; -# int hash; +# int f_hash; # (optional) key hash, if hard to recompute # } # # struct dicttable { @@ -61,39 +59,10 @@ def rtyper_makekey(self): return (self.__class__, self.dictdef.dictkey, self.dictdef.dictvalue) -class DictTrait: - # avoid explosion of one helper function per repr - # vs. layout and functions - - def __init__(self, dictrepr): - self.DICT = dictrepr.DICT - self.DICTENTRYARRAY = dictrepr.DICTENTRYARRAY - self.custom_eq_hash = False - self.ll_keyhash = dictrepr.ll_keyhash - self.ll_keyeq = dictrepr.ll_keyeq - - def _freeze_(self): - return True - - def __repr__(self): - return "DictT %s" % self.DICT._short_name() - -def dict_trait(rtyper, dictrepr): - if dictrepr.custom_eq_hash: # in this case use there is not much point in not just using the repr - return dictrepr - - key = (dictrepr.DICT, dictrepr.ll_keyhash, dictrepr.ll_keyeq) - try: - return rtyper._dict_traits[key] - except KeyError: - trait = DictTrait(dictrepr) - rtyper._dict_traits[key] = trait - return trait - class DictRepr(rmodel.Repr): - def __init__(self, rtyper, key_repr, value_repr, dictkey=None, dictvalue=None, + def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, custom_eq_hash=None): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() @@ -113,7 +82,6 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash - self._trait = None # cache for get_trait # setup() needs to be called to finish this initialization def pickrepr(self, item_repr): @@ -142,12 +110,77 @@ if isinstance(self.DICT, lltype.GcForwardReference): self.DICTKEY = self.key_repr.lowleveltype self.DICTVALUE = self.value_repr.lowleveltype - self.DICTENTRY = lltype.Struct("dictentry", - ("key", self.DICTKEY), - ("hash", lltype.Signed), - ("valid", lltype.Bool), - ("everused", lltype.Bool), - ("value", self.DICTVALUE)) + + # compute the shape of the DICTENTRY structure + entryfields = [] + entrymeths = { + 'must_clear_key': (isinstance(self.DICTKEY, lltype.Ptr) + and self.DICTKEY._needsgc()), + 'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr) + and self.DICTVALUE._needsgc()), + } + + # * the key + entryfields.append(("key", self.DICTKEY)) + + # * if NULL is not a valid ll value for the key or the value + # field of the entry, it can be used as a marker for + # never-used entries. Otherwise, we need an explicit flag. + s_key = self.dictkey.s_value + s_value = self.dictvalue.s_value + nullkeymarker = not self.key_repr.can_ll_be_null(s_key) + nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + + if nullkeymarker: + entrymeths['everused'] = ll_everused_from_key + elif nullvaluemarker: + entrymeths['everused'] = ll_everused_from_value + else: + entryfields.append(("f_everused", lltype.Bool)) + entrymeths['everused'] = ll_everused_from_flag + + # * if the key or the value can also contain a "dummy" non-null + # marker, we use it for deleted entries. + rtyper = self.rtyper + dummy_obj = self.key_repr.get_ll_dummyval_obj(rtyper, s_key) + if dummy_obj: + entrymeths['dummy_obj'] = dummy_obj + entrymeths['valid'] = ll_valid_from_key + entrymeths['mark_deleted'] = ll_mark_deleted_in_key + # the key is overwritten by 'dummy' when the entry is deleted + entrymeths['must_clear_key'] = False + else: + dummy_obj = self.value_repr.get_ll_dummyval_obj(rtyper, + s_value) + if dummy_obj: + entrymeths['dummy_obj'] = dummy_obj + entrymeths['valid'] = ll_valid_from_value + entrymeths['mark_deleted'] = ll_mark_deleted_in_value + # value is overwritten by 'dummy' when entry is deleted + entrymeths['must_clear_value'] = False + else: + entryfields.append(("f_valid", lltype.Bool)) + entrymeths['valid'] = ll_valid_from_flag + entrymeths['mark_deleted'] = ll_mark_deleted_in_flag + + # * the value + entryfields.append(("value", self.DICTVALUE)) + + # * the hash, if needed + if self.custom_eq_hash: + fasthashfn = None + else: + fasthashfn = self.key_repr.get_ll_fasthash_function() + if fasthashfn is None: + entryfields.append(("f_hash", lltype.Signed)) + entrymeths['hash'] = ll_hash_from_cache + else: + entrymeths['hash'] = ll_hash_recomputed + entrymeths['fasthashfn'] = fasthashfn + + # Build the lltype data structures + self.DICTENTRY = lltype.Struct("dictentry", adtmeths=entrymeths, + *entryfields) self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY) fields = [ ("num_items", lltype.Signed), ("num_pristine_entries", lltype.Signed), @@ -156,11 +189,25 @@ self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr() fields.extend([ ("fnkeyeq", self.r_rdict_eqfn.lowleveltype), ("fnkeyhash", self.r_rdict_hashfn.lowleveltype) ]) - self.DICT.become(lltype.GcStruct("dicttable", *fields)) - if 'll_keyhash' not in self.__dict__ and not self.custom_eq_hash: - # figure out which functions must be used to hash and compare keys - self.ll_keyeq = self.key_repr.get_ll_eq_function() # can be None - self.ll_keyhash = self.key_repr.get_ll_hash_function() + adtmeths = { + 'keyhash': ll_keyhash_custom, + 'keyeq': ll_keyeq_custom, + 'r_rdict_eqfn': self.r_rdict_eqfn, + 'r_rdict_hashfn': self.r_rdict_hashfn, + } + else: + # figure out which functions must be used to hash and compare + ll_keyhash = self.key_repr.get_ll_hash_function() + ll_keyeq = self.key_repr.get_ll_eq_function() # can be None + ll_keyhash = lltype.staticAdtMethod(ll_keyhash) + if ll_keyeq is not None: + ll_keyeq = lltype.staticAdtMethod(ll_keyeq) + adtmeths = { + 'keyhash': ll_keyhash, + 'keyeq': ll_keyeq, + } + self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, + *fields)) def recast_value(self, llops, v): return llops.convertvar(v, self.value_repr, self.external_value_repr) @@ -168,11 +215,6 @@ def recast_key(self, llops, v): return llops.convertvar(v, self.key_repr, self.external_key_repr) - def get_trait(self): - if self._trait is None: - self._trait = dict_trait(self.rtyper, self) - return self._trait - def convert_const(self, dictobj): # get object from bound dict methods #dictobj = getattr(dictobj, '__self__', dictobj) @@ -185,7 +227,7 @@ return self.dict_cache[key] except KeyError: self.setup() - l_dict = ll_newdict(self) + l_dict = ll_newdict_size(self.DICT, len(dictobj)) self.dict_cache[key] = l_dict r_key = self.key_repr r_value = self.value_repr @@ -196,38 +238,20 @@ if self.r_rdict_hashfn.lowleveltype != lltype.Void: l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash) l_dict.fnkeyhash = l_fn - # a dummy object with ll_keyeq and ll_keyhash methods to - # pass to ll_dict_setitem() - class Dummy: - custom_eq_hash = False - def ll_keyeq(self, key1, key2): - # theory: all low-level values we consider as keys - # can be compared by equality (i.e. identity for - # pointers) because the r_dict itself should have - # ensured that it does not store duplicate equal keys. - return key1 == key2 - def ll_keyhash(self, key): - # theoretically slow, but well (see theory above) - for llkey, hash in self.cache: - if key == llkey: - return hash - raise TyperError("hash missing in convert_const(%r)" % - (dictobj,)) - dummy = Dummy() - dummy.cache = [] for dictkeycontainer, dictvalue in dictobj._dict.items(): llkey = r_key.convert_const(dictkeycontainer.key) llvalue = r_value.convert_const(dictvalue) - dummy.cache.insert(0, (llkey, dictkeycontainer.hash)) - ll_dict_setitem(l_dict, llkey, llvalue, dummy) + ll_dict_insertclean(l_dict, llkey, llvalue, + dictkeycontainer.hash) return l_dict else: for dictkey, dictvalue in dictobj.items(): llkey = r_key.convert_const(dictkey) llvalue = r_value.convert_const(dictvalue) - ll_dict_setitem(l_dict, llkey, llvalue, self) + ll_dict_insertclean(l_dict, llkey, llvalue, + l_dict.keyhash(llkey)) return l_dict def rtype_len(self, hop): @@ -244,22 +268,19 @@ def rtype_method_get(self, hop): v_dict, v_key, v_default = hop.inputargs(self, self.key_repr, self.value_repr) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default, ctrait) + v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default) return self.recast_value(hop.llops, v_res) def rtype_method_copy(self, hop): v_dict, = hop.inputargs(self) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - return hop.gendirectcall(ll_copy, v_dict, ctrait) + return hop.gendirectcall(ll_copy, v_dict) def rtype_method_update(self, hop): v_dic1, v_dic2 = hop.inputargs(self, self) - ctrait = hop.inputconst(lltype.Void, self.get_trait()) hop.exception_cannot_occur() - return hop.gendirectcall(ll_update, v_dic1, v_dic2, ctrait) + return hop.gendirectcall(ll_update, v_dic1, v_dic2) def _rtype_method_kvi(self, hop, spec): v_dic, = hop.inputargs(self) @@ -299,28 +320,24 @@ def rtype_getitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key, ctrait) + v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key) return r_dict.recast_value(hop.llops, v_res) def rtype_delitem((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - return hop.gendirectcall(ll_dict_delitem, v_dict, v_key, ctrait) + return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value, ctrait) + hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value) def rtype_contains((r_dict, r_key), hop): v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - return hop.gendirectcall(ll_contains, v_dict, v_key, ctrait) + return hop.gendirectcall(ll_contains, v_dict, v_key) class __extend__(pairtype(DictRepr, DictRepr)): def convert_from_to((r_dict1, r_dict2), v, llops): @@ -342,6 +359,56 @@ # be direct_call'ed from rtyped flow graphs, which means that they will # get flowed and annotated, mostly with SomePtr. +def ll_everused_from_flag(entry): + return entry.f_everused + +def ll_everused_from_key(entry): + return bool(entry.key) + +def ll_everused_from_value(entry): + return bool(entry.value) + +def ll_valid_from_flag(entry): + return entry.f_valid + +def ll_mark_deleted_in_flag(entry): + entry.f_valid = False + +def ll_valid_from_key(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + return entry.everused() and entry.key != dummy + +def ll_mark_deleted_in_key(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + entry.key = dummy + +def ll_valid_from_value(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + return entry.everused() and entry.value != dummy + +def ll_mark_deleted_in_value(entry): + ENTRY = lltype.typeOf(entry).TO + dummy = ENTRY.dummy_obj.ll_dummy_value + entry.value = dummy + +def ll_hash_from_cache(entry): + return entry.f_hash + +def ll_hash_recomputed(entry): + ENTRY = lltype.typeOf(entry).TO + return ENTRY.fasthashfn(entry.key) + +def ll_keyhash_custom(d, key): + DICT = lltype.typeOf(d).TO + return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key) + +def ll_keyeq_custom(d, key1, key2): + DICT = lltype.typeOf(d).TO + return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2) + def dum_keys(): pass def dum_values(): pass def dum_items():pass @@ -356,51 +423,69 @@ # check if a dict is True, allowing for None return bool(d) and d.num_items != 0 -def ll_dict_getitem(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - if entry.valid: +def ll_dict_getitem(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + if entry.valid(): return entry.value else: raise KeyError -def ll_dict_setitem(d, key, value, dictrait): - entry = ll_dict_lookup(d, key, dictrait) +def ll_dict_setitem(d, key, value): + hash = d.keyhash(key) + entry = ll_dict_lookup(d, key, hash) + everused = entry.everused() + valid = entry.valid() + # set up the new entry + ENTRY = lltype.typeOf(entry).TO entry.value = value - if entry.valid: + if valid: return - if dictrait.custom_eq_hash: - hash = hlinvoke(dictrait.r_rdict_hashfn, d.fnkeyhash, key) - else: - hash = dictrait.ll_keyhash(key) - entry.key = key - entry.hash = hash - entry.valid = True + entry.key = key + if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash + if hasattr(ENTRY, 'f_valid'): entry.f_valid = True d.num_items += 1 - if not entry.everused: - entry.everused = True + if not everused: + if hasattr(ENTRY, 'f_everused'): entry.f_everused = True d.num_pristine_entries -= 1 if d.num_pristine_entries <= len(d.entries) / 3: - ll_dict_resize(d, dictrait) + ll_dict_resize(d) -def ll_dict_delitem(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - if not entry.valid: +def ll_dict_insertclean(d, key, value, hash): + # Internal routine used by ll_dict_resize() to insert an item which is + # known to be absent from the dict. This routine also assumes that + # the dict contains no deleted entries. This routine has the advantage + # of never calling d.keyhash() and d.keyeq(), so it cannot call back + # to user code. ll_dict_insertclean() doesn't resize the dict, either. + entry = ll_dict_lookup_clean(d, hash) + ENTRY = lltype.typeOf(entry).TO + entry.value = value + entry.key = key + if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash + if hasattr(ENTRY, 'f_valid'): entry.f_valid = True + if hasattr(ENTRY, 'f_everused'): entry.f_everused = True + d.num_items += 1 + d.num_pristine_entries -= 1 + +def ll_dict_delitem(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + if not entry.valid(): raise KeyError - entry.valid = False + entry.mark_deleted() d.num_items -= 1 - # clear the key and the value if they are pointers - keytype = lltype.typeOf(entry).TO.key - if isinstance(keytype, lltype.Ptr): - key = entry.key # careful about destructor side effects - entry.key = lltype.nullptr(keytype.TO) - valuetype = lltype.typeOf(entry).TO.value - if isinstance(valuetype, lltype.Ptr): - entry.value = lltype.nullptr(valuetype.TO) + # clear the key and the value if they are GC pointers + ENTRY = lltype.typeOf(entry).TO + if ENTRY.must_clear_key: + key = entry.key # careful about destructor side effects: + # keep key alive until entry.value has also + # been zeroed (if it must be) + entry.key = lltype.nullptr(ENTRY.key.TO) + if ENTRY.must_clear_value: + entry.value = lltype.nullptr(ENTRY.value.TO) num_entries = len(d.entries) if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4: - ll_dict_resize(d, dictrait) + ll_dict_resize(d) -def ll_dict_resize(d, dictrait): +def ll_dict_resize(d): old_entries = d.entries old_size = len(old_entries) # make a 'new_size' estimate and shrink it if there are many @@ -409,49 +494,41 @@ while new_size > DICT_INITSIZE and d.num_items < new_size / 4: new_size /= 2 d.entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size) - d.num_pristine_entries = new_size - d.num_items + d.num_items = 0 + d.num_pristine_entries = new_size i = 0 while i < old_size: entry = old_entries[i] - if entry.valid: - new_entry = ll_dict_lookup(d, entry.key, dictrait) - new_entry.key = entry.key - new_entry.hash = entry.hash - new_entry.value = entry.value - new_entry.valid = True - new_entry.everused = True + if entry.valid(): + ll_dict_insertclean(d, entry.key, entry.value, entry.hash()) i += 1 # ------- a port of CPython's dictobject.c's lookdict implementation ------- PERTURB_SHIFT = 5 -def ll_dict_lookup(d, key, dictrait): - if dictrait.custom_eq_hash: - hash = hlinvoke(dictrait.r_rdict_hashfn, d.fnkeyhash, key) - else: - hash = dictrait.ll_keyhash(key) +def ll_dict_lookup(d, key, hash): entries = d.entries mask = len(entries) - 1 i = r_uint(hash & mask) # do the first try before any looping entry = entries[i] - if entry.valid: + if entry.valid(): checkingkey = entry.key if checkingkey == key: return entry # found the entry - if entry.hash == hash: - if dictrait.custom_eq_hash: - res = hlinvoke(dictrait.r_rdict_eqfn, d.fnkeyeq, checkingkey, key) + if d.keyeq is not None and entry.hash() == hash: + # correct hash, maybe the key is e.g. a different pointer to + # an equal object + found = d.keyeq(checkingkey, key) + if 1: # XXX not always needed if (entries != d.entries or - not entry.valid or entry.key != checkingkey): + not entry.valid() or entry.key != checkingkey): # the compare did major nasty stuff to the dict: start over - return ll_dict_lookup(d, key, dictrait) - else: - res = dictrait.ll_keyeq is not None and dictrait.ll_keyeq(checkingkey, key) - if res: + return ll_dict_lookup(d, key, hash) + if found: return entry # found the entry freeslot = lltype.nullptr(lltype.typeOf(entry).TO) - elif entry.everused: + elif entry.everused(): freeslot = entry else: return entry # pristine entry -- lookup failed @@ -462,44 +539,66 @@ while 1: i = ((i << 2) + i + perturb + 1) & mask entry = entries[i] - if not entry.everused: + if not entry.everused(): return freeslot or entry - elif entry.valid: + elif entry.valid(): checkingkey = entry.key if checkingkey == key: return entry - if entry.hash == hash: - if dictrait.custom_eq_hash: - res = hlinvoke(dictrait.r_rdict_eqfn, d.fnkeyeq, checkingkey, key) + if d.keyeq is not None and entry.hash() == hash: + # correct hash, maybe the key is e.g. a different pointer to + # an equal object + found = d.keyeq(checkingkey, key) + if 1: # XXX not always needed if (entries != d.entries or - not entry.valid or entry.key != checkingkey): - # the compare did major nasty stuff to the dict: start over - return ll_dict_lookup(d, key, dictrait) - else: - res = dictrait.ll_keyeq is not None and dictrait.ll_keyeq(checkingkey, key) - if res: - return entry + not entry.valid() or entry.key != checkingkey): + # the compare did major nasty stuff to the dict: + # start over + return ll_dict_lookup(d, key, hash) + if found: + return entry # found the entry elif not freeslot: freeslot = entry perturb >>= PERTURB_SHIFT +def ll_dict_lookup_clean(d, hash): + # a simplified version of ll_dict_lookup() which assumes that the + # key is new, and the dictionary doesn't contain deleted entries. + # It only find the next free slot for the given hash. + entries = d.entries + mask = len(entries) - 1 + i = r_uint(hash & mask) + entry = entries[i] + perturb = r_uint(hash) + while entry.everused(): + i = ((i << 2) + i + perturb + 1) & mask + entry = entries[i] + perturb >>= PERTURB_SHIFT + return entry + # ____________________________________________________________ # # Irregular operations. DICT_INITSIZE = 8 -def ll_newdict(dictrait): - d = lltype.malloc(dictrait.DICT) - d.entries = lltype.malloc(dictrait.DICTENTRYARRAY, DICT_INITSIZE) - d.num_items = 0 # but still be explicit +def ll_newdict(DICT): + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE) + #d.num_items = 0 -- defaults d.num_pristine_entries = DICT_INITSIZE return d -def ll_copy_extra_data(targetdict, sourcedict, dictrait): - if dictrait.custom_eq_hash: - targetdict.fnkeyeq = sourcedict.fnkeyeq - targetdict.fnkeyhash = sourcedict.fnkeyhash +def ll_newdict_size(DICT, length_estimate): + length_estimate = (length_estimate // 2) * 3 + n = DICT_INITSIZE + while n < length_estimate: + n *= 2 + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, n) + #d.num_items = 0 -- defaults + d.num_pristine_entries = DICT_INITSIZE + return d def rtype_newdict(hop): hop.inputargs() # no arguments expected @@ -507,8 +606,8 @@ if r_dict == robject.pyobj_repr: # special case: SomeObject: SomeObject dicts! cdict = hop.inputconst(robject.pyobj_repr, dict) return hop.genop('simple_call', [cdict], resulttype = robject.pyobj_repr) - ctrait = hop.inputconst(lltype.Void, r_dict.get_trait()) - v_result = hop.gendirectcall(ll_newdict, ctrait) + cDICT = hop.inputconst(lltype.Void, r_dict.DICT) + v_result = hop.gendirectcall(ll_newdict, cDICT) return v_result def rtype_r_dict(hop): @@ -517,9 +616,9 @@ raise TyperError("r_dict() call does not return an r_dict instance") v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, r_dict.r_rdict_hashfn) - ctrait = hop.inputconst(lltype.Void, r_dict) + cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() - v_result = hop.gendirectcall(ll_newdict, ctrait) + v_result = hop.gendirectcall(ll_newdict, cDICT) if r_dict.r_rdict_eqfn.lowleveltype != lltype.Void: cname = hop.inputconst(lltype.Void, 'fnkeyeq') hop.genop('setfield', [v_result, cname, v_eqfn]) @@ -579,7 +678,7 @@ while index < entries_len: entry = entries[index] index = index + 1 - if entry.valid: + if entry.valid(): iter.index = index if func is dum_items: r = lltype.malloc(RETURNTYPE.TO) @@ -597,49 +696,51 @@ # _____________________________________________________________ # methods -def ll_get(dict, key, default, dictrait): - entry = ll_dict_lookup(dict, key, dictrait) - if entry.valid: +def ll_get(dict, key, default): + entry = ll_dict_lookup(dict, key, dict.keyhash(key)) + if entry.valid(): return entry.value else: return default -def ll_copy(dict, dictrait): +def ll_copy(dict): + DICT = lltype.typeOf(dict).TO dictsize = len(dict.entries) - d = lltype.malloc(dictrait.DICT) - d.entries = lltype.malloc(dictrait.DICTENTRYARRAY, dictsize) + d = lltype.malloc(DICT) + d.entries = lltype.malloc(DICT.entries.TO, dictsize) d.num_items = dict.num_items d.num_pristine_entries = dict.num_pristine_entries - ll_copy_extra_data(d, dict, dictrait) + if hasattr(DICT, 'fnkeyeq'): d.fnkeyeq = dict.fnkeyeq + if hasattr(DICT, 'fnkeyhash'): d.fnkeyhash = dict.fnkeyhash i = 0 while i < dictsize: d_entry = d.entries[i] entry = dict.entries[i] + ENTRY = lltype.typeOf(entry).TO d_entry.key = entry.key - d_entry.hash = entry.hash + if hasattr(ENTRY, 'f_valid'): d_entry.f_valid = entry.f_valid + if hasattr(ENTRY, 'f_everused'): d_entry.f_everused = entry.f_everused d_entry.value = entry.value - d_entry.valid = entry.valid - d_entry.everused = entry.everused + if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash i += 1 return d def ll_clear(d): if len(d.entries) == d.num_pristine_entries == DICT_INITSIZE: return - DICTPTR = lltype.typeOf(d) - d.entries = lltype.malloc(DICTPTR.TO.entries.TO, DICT_INITSIZE) + DICT = lltype.typeOf(d).TO + d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE) d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE -def ll_update(dic1, dic2, dictrait): - # XXX warning, no protection against ll_dict_setitem mutating dic2 - d2len = len(dic2.entries) +def ll_update(dic1, dic2): entries = dic2.entries + d2len = len(entries) i = 0 while i < d2len: entry = entries[i] - if entry.valid: - ll_dict_setitem(dic1, entry.key, entry.value, dictrait) + if entry.valid(): + ll_dict_setitem(dic1, entry.key, entry.value) i += 1 # this is an implementation of keys(), values() and items() @@ -655,14 +756,14 @@ def ll_kvi(dic, LIST, func): res = LIST.ll_newlist(dic.num_items) - dlen = len(dic.entries) entries = dic.entries + dlen = len(entries) items = res.ll_items() i = 0 p = 0 while i < dlen: entry = entries[i] - if entry.valid: + if entry.valid(): ELEM = lltype.typeOf(items).TO.OF if func is dum_items: r = lltype.malloc(ELEM.TO) @@ -672,11 +773,11 @@ elif func is dum_keys: items[p] = recast(ELEM, entry.key) elif func is dum_values: - items[p] = recast(ELEM, entry.value) + items[p] = recast(ELEM, entry.value) p += 1 i += 1 return res -def ll_contains(d, key, dictrait): - entry = ll_dict_lookup(d, key, dictrait) - return entry.valid +def ll_contains(d, key): + entry = ll_dict_lookup(d, key, d.keyhash(key)) + return entry.valid() Modified: pypy/dist/pypy/rpython/rfloat.py ============================================================================== --- pypy/dist/pypy/rpython/rfloat.py (original) +++ pypy/dist/pypy/rpython/rfloat.py Thu Mar 23 13:24:40 2006 @@ -154,8 +154,6 @@ v = (v - float(hipart)) * TAKE_NEXT x = hipart + int(v) + (expo << 15) return x -ll_hash_float.cache_in_dict = True - # # _________________________ Conversions _________________________ Modified: pypy/dist/pypy/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/dist/pypy/rpython/rint.py Thu Mar 23 13:24:40 2006 @@ -225,6 +225,17 @@ def get_ll_hash_function(self): return ll_hash_int + get_ll_fasthash_function = get_ll_hash_function + + def get_ll_dummyval_obj(self, rtyper, s_value): + # if >= 0, then all negative values are special + if s_value.nonneg and not s_value.unsigned: + return signed_repr # whose ll_dummy_value is -1 + else: + return None + + ll_dummy_value = -1 + def rtype_chr(_, hop): vlist = hop.inputargs(Signed) if hop.has_implicit_exception(ValueError): @@ -416,9 +427,11 @@ j += 1 return result -def ll_hash_int(n): +def ll_identity(n): return n +ll_hash_int = ll_identity + def ll_check_chr(n): if 0 <= n <= 255: return Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Thu Mar 23 13:24:40 2006 @@ -5,6 +5,7 @@ from pypy.rpython.lltypesystem.lltype import \ Void, Bool, Float, Signed, Char, UniChar, \ typeOf, LowLevelType, Ptr, PyObject, isCompatibleType +from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype from pypy.rpython.error import TyperError, MissingRTypeOperation @@ -135,12 +136,41 @@ def get_ll_hash_function(self): """Return a hash(x) function for low-level values of this Repr. - As a hint, the function can have a flag 'cache_in_dict=True' if it - makes non-trivial computations and its result should be cached in - dictionary entries. """ raise TyperError, 'no hashing function for %r' % self + def get_ll_fasthash_function(self): + """Return a 'fast' hash(x) function for low-level values of this + Repr. The function can assume that 'x' is already stored as a + key in a dict. get_ll_fasthash_function() should return None if + the hash should rather be cached in the dict entry. + """ + return None + + def can_ll_be_null(self, s_value): + """Check if the low-level repr can take the value 0/NULL. + The annotation s_value is provided as a hint because it may + contain more information than the Repr. + """ + return True # conservative + + def get_ll_dummyval_obj(self, rtyper, s_value): + """A dummy value is a special low-level value, not otherwise + used. It should not be the NULL value even if it is special. + This returns either None, or a hashable object that has a + (possibly lazy) attribute 'll_dummy_value'. + The annotation s_value is provided as a hint because it may + contain more information than the Repr. + """ + T = self.lowleveltype + if (isinstance(T, lltype.Ptr) and + isinstance(T.TO, (lltype.Struct, + lltype.Array, + lltype.ForwardReference))): + return DummyValueBuilder(rtyper, T.TO) + else: + return None + def rtype_bltn_list(self, hop): raise TyperError, 'no list() support for %r' % self @@ -310,6 +340,7 @@ lowleveltype = Void def get_ll_eq_function(self): return None def get_ll_hash_function(self): return ll_hash_void + get_ll_fasthash_function = get_ll_hash_function impossible_repr = VoidRepr() # ____________________________________________________________ @@ -390,7 +421,43 @@ return item_repr, rclass.getinstancerepr(rtyper, None) else: return item_repr, item_repr - + + +class DummyValueBuilder(object): + + def __init__(self, rtyper, TYPE): + self.rtyper = rtyper + self.TYPE = TYPE + + def _freeze_(self): + return True + + def __hash__(self): + return hash(self.TYPE) + + def __eq__(self, other): + return (isinstance(other, DummyValueBuilder) and + self.rtyper is other.rtyper and + self.TYPE == other.TYPE) + + def __ne__(self, other): + return not (self == other) + + def build_ll_dummy_value(self): + TYPE = self.TYPE + try: + return self.rtyper.cache_dummy_values[TYPE] + except KeyError: + # generate a dummy ptr to an immortal placeholder struct/array + if TYPE._is_varsize(): + p = lltype.malloc(TYPE, 0, immortal=True) + else: + p = lltype.malloc(TYPE, immortal=True) + self.rtyper.cache_dummy_values[TYPE] = p + return p + + ll_dummy_value = property(build_ll_dummy_value) + # logging/warning Modified: pypy/dist/pypy/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/dist/pypy/rpython/rstr.py Thu Mar 23 13:24:40 2006 @@ -80,6 +80,16 @@ def get_ll_hash_function(self): return ll_strhash + def get_ll_fasthash_function(self): + return ll_strfasthash + + def can_ll_be_null(self, s_value): + if self is string_repr: + return s_value.can_be_none() + else: + return True # for CharRepr/UniCharRepr subclasses, + # where NULL is always valid: it is chr(0) + def rtype_len(_, hop): v_str, = hop.inputargs(string_repr) return hop.gendirectcall(ll_strlen, v_str) @@ -404,6 +414,8 @@ def get_ll_hash_function(self): return ll_char_hash + get_ll_fasthash_function = get_ll_hash_function + def ll_str(self, ch): return ll_chr2str(ch) @@ -476,6 +488,8 @@ def get_ll_hash_function(self): return ll_unichar_hash + get_ll_fasthash_function = get_ll_hash_function + ## def rtype_len(_, hop): ## return hop.inputconst(Signed, 1) ## @@ -641,6 +655,9 @@ s.hash = x return x +def ll_strfasthash(s): + return s.hash # assumes that the hash is already computed + def ll_strconcat(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Thu Mar 23 13:24:40 2006 @@ -81,7 +81,6 @@ source = source % body exec source in miniglobals ll_hash = miniglobals['ll_hash'] - ll_hash.cache_in_dict = True _gen_hash_function_cache[key] = ll_hash return ll_hash @@ -127,6 +126,9 @@ def get_ll_hash_function(self): return gen_hash_function(self.items_r) + def can_ll_be_null(self, s_value): + return False + def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) Modified: pypy/dist/pypy/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/dist/pypy/rpython/rtyper.py Thu Mar 23 13:24:40 2006 @@ -59,6 +59,7 @@ self.concrete_calltables = {} self.class_pbc_attributes = {} self.oo_meth_impls = {} + self.cache_dummy_values = {} self.typererrors = [] self.typererror_count = 0 # make the primitive_to_repr constant mapping Modified: pypy/dist/pypy/rpython/test/test_rdict.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rdict.py (original) +++ pypy/dist/pypy/rpython/test/test_rdict.py Thu Mar 23 13:24:40 2006 @@ -123,7 +123,7 @@ res = interpret(func2, [ord(x), ord(y)]) for i in range(len(res.entries)): - assert not (res.entries[i].everused and not res.entries[i].valid) + assert not (res.entries[i].everused() and not res.entries[i].valid()) def func3(c0, c1, c2, c3, c4, c5, c6, c7): d = {} @@ -143,7 +143,7 @@ for i in range(rdict.DICT_INITSIZE)]) count_frees = 0 for i in range(len(res.entries)): - if not res.entries[i].everused: + if not res.entries[i].everused(): count_frees += 1 assert count_frees >= 3 @@ -437,6 +437,7 @@ Could be useful to detect problems associated with specific usage patterns.""" import random x = random.random() + print 'random seed: %r' % (x,) for i in range(12000): r = 3.4 + i/20000.0 x = r*x - x*x @@ -444,9 +445,13 @@ yield x def test_stress(): - dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr) + from pypy.annotation.dictdef import DictKey, DictValue + from pypy.annotation import model as annmodel + dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr, + DictKey(None, annmodel.SomeInteger()), + DictValue(None, annmodel.SomeInteger())) dictrepr.setup() - l_dict = rdict.ll_newdict(dictrepr) + l_dict = rdict.ll_newdict(dictrepr.DICT) referencetable = [None] * 400 referencelength = 0 value = 0 @@ -454,7 +459,7 @@ def complete_check(): for n, refvalue in zip(range(len(referencetable)), referencetable): try: - gotvalue = rdict.ll_dict_getitem(l_dict, n, dictrepr) + gotvalue = rdict.ll_dict_getitem(l_dict, n) except KeyError: assert refvalue is None else: @@ -464,18 +469,18 @@ n = int(x*100.0) # 0 <= x < 400 op = repr(x)[-1] if op <= '2' and referencetable[n] is not None: - rdict.ll_dict_delitem(l_dict, n, dictrepr) + rdict.ll_dict_delitem(l_dict, n) referencetable[n] = None referencelength -= 1 elif op <= '6': - rdict.ll_dict_setitem(l_dict, n, value, dictrepr) + rdict.ll_dict_setitem(l_dict, n, value) if referencetable[n] is None: referencelength += 1 referencetable[n] = value value += 1 else: try: - gotvalue = rdict.ll_dict_getitem(l_dict, n, dictrepr) + gotvalue = rdict.ll_dict_getitem(l_dict, n) except KeyError: assert referencetable[n] is None else: @@ -486,6 +491,94 @@ assert l_dict.num_items == referencelength complete_check() +# ____________________________________________________________ + +def test_opt_nullkeymarker(): + def f(): + d = {"hello": None} + d["world"] = None + return "hello" in d, d + res = interpret(f, []) + assert res.item0 == True + DICT = lltype.typeOf(res.item1).TO + assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None string keys + assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strings have a dummy + +def test_opt_nullvaluemarker(): + def f(n): + d = {-5: "abcd"} + d[123] = "def" + return len(d[n]), d + res = interpret(f, [-5]) + assert res.item0 == 4 + DICT = lltype.typeOf(res.item1).TO + assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None str values + assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strs have a dummy + +def test_opt_nonullmarker(): + class A: + pass + def f(n): + if n > 5: + a = A() + else: + a = None + d = {a: -5441} + d[A()] = n+9872 + return d[a], d + res = interpret(f, [-5]) + assert res.item0 == -5441 + DICT = lltype.typeOf(res.item1).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # can-be-None A instances + assert not hasattr(DICT.entries.TO.OF, 'f_valid')# with a dummy A instance + + res = interpret(f, [6]) + assert res.item0 == -5441 + +def test_opt_nonnegint_dummy(): + def f(n): + d = {n: 12} + d[-87] = 24 + del d[n] + return len(d.copy()), d[-87], d + res = interpret(f, [5]) + assert res.item0 == 1 + assert res.item1 == 24 + DICT = lltype.typeOf(res.item2).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero + assert not hasattr(DICT.entries.TO.OF, 'f_valid')# nonneg int: dummy -1 + +def test_opt_no_dummy(): + def f(n): + d = {n: 12} + d[-87] = -24 + del d[n] + return len(d.copy()), d[-87], d + res = interpret(f, [5]) + assert res.item0 == 1 + assert res.item1 == -24 + DICT = lltype.typeOf(res.item2).TO + assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero + assert hasattr(DICT.entries.TO.OF, 'f_valid') # no dummy available + +def test_opt_multiple_identical_dicts(): + def f(n): + s = "x" * n + d1 = {s: 12} + d2 = {s: 24} + d3 = {s: 36} + d1["a"] = d2[s] # 24 + d3[s] += d1["a"] # 60 + d2["bc"] = d3[s] # 60 + return d2["bc"], d1, d2, d3 + res = interpret(f, [5]) + assert res.item0 == 60 + # all three dicts should use the same low-level type + assert lltype.typeOf(res.item1) == lltype.typeOf(res.item2) + assert lltype.typeOf(res.item1) == lltype.typeOf(res.item3) + +# ____________________________________________________________ + def test_id_instances_keys(): class A: pass @@ -560,4 +653,14 @@ res = interpret(f, [2]) assert res == f(2) - +def test_dict_of_dict(): + def f(n): + d = {} + d[5] = d + d[6] = {} + return len(d[n]) + + res = interpret(f, [5]) + assert res == 2 + res = interpret(f, [6]) + assert res == 0 From arigo at codespeak.net Thu Mar 23 13:44:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 13:44:06 +0100 (CET) Subject: [pypy-svn] r24879 - pypy/dist/pypy/rpython Message-ID: <20060323124406.5721A10142@code0.codespeak.net> Author: arigo Date: Thu Mar 23 13:44:05 2006 New Revision: 24879 Modified: pypy/dist/pypy/rpython/rdict.py Log: Only check if the dictionary was mutated by the call to keyeq() in the case of r_dict()s, not for normal RPython dicts. Indeed, none of the get_ll_eq_function() so far has visible side effects. Modified: pypy/dist/pypy/rpython/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/rdict.py (original) +++ pypy/dist/pypy/rpython/rdict.py Thu Mar 23 13:44:05 2006 @@ -194,6 +194,7 @@ 'keyeq': ll_keyeq_custom, 'r_rdict_eqfn': self.r_rdict_eqfn, 'r_rdict_hashfn': self.r_rdict_hashfn, + 'paranoia': True, } else: # figure out which functions must be used to hash and compare @@ -203,8 +204,9 @@ if ll_keyeq is not None: ll_keyeq = lltype.staticAdtMethod(ll_keyeq) adtmeths = { - 'keyhash': ll_keyhash, - 'keyeq': ll_keyeq, + 'keyhash': ll_keyhash, + 'keyeq': ll_keyeq, + 'paranoia': False, } self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields)) @@ -507,6 +509,7 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): + DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = r_uint(hash & mask) @@ -520,7 +523,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if 1: # XXX not always needed + if DICT.paranoia: if (entries != d.entries or not entry.valid() or entry.key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -549,7 +552,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if 1: # XXX not always needed + if DICT.paranoia: if (entries != d.entries or not entry.valid() or entry.key != checkingkey): # the compare did major nasty stuff to the dict: From pedronis at codespeak.net Thu Mar 23 15:32:13 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 15:32:13 +0100 (CET) Subject: [pypy-svn] r24882 - pypy/dist/pypy/translator/microbench Message-ID: <20060323143213.C671F1012D@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 15:32:12 2006 New Revision: 24882 Modified: pypy/dist/pypy/translator/microbench/test_bltn.py Log: another micronbench I had around. Modified: pypy/dist/pypy/translator/microbench/test_bltn.py ============================================================================== --- pypy/dist/pypy/translator/microbench/test_bltn.py (original) +++ pypy/dist/pypy/translator/microbench/test_bltn.py Thu Mar 23 15:32:12 2006 @@ -10,3 +10,13 @@ while c < n: x = sin(x) c += 1 + +def test_call_fabs(): + from math import fabs + + x = -1.0 + c = 0 + n = N + while c < n: + x = fabs(x) + c += 1 From ericvrp at codespeak.net Thu Mar 23 16:23:50 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 23 Mar 2006 16:23:50 +0100 (CET) Subject: [pypy-svn] r24883 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060323152350.4CDA110137@code0.codespeak.net> Author: ericvrp Date: Thu Mar 23 16:23:48 2006 New Revision: 24883 Added: pypy/dist/pypy/translator/llvm/pyllvm/test/__init__.py pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Added pyllvm tests and trying to replace already generated function with new versions. Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Thu Mar 23 16:23:48 2006 @@ -27,15 +27,59 @@ } PyExecutionEngine; +/* +XXX we should probably support parsing one function at a time too. +This would enable use to use self->exec->recompileAndRelinkFunction(Function* F) +to support rebinding to a new (more blocks?) function. (or self modifying code) +*/ static PyObject *ee_parse(PyExecutionEngine *self, PyObject *args) { - char *llcode; - if (!PyArg_ParseTuple(args, "s", &llcode)) { - return NULL; + // check number of parameters + if (PyTuple_Size(args) < 1 or PyTuple_Size(args) > 2) { + PyErr_SetString(PyExc_TypeError, "expected one or two parameters"); + return NULL; + } + + // get first parameter (llcode) + PyObject *pyllcode = PyTuple_GetItem(args, 0); + if (!PyString_Check(pyllcode)) { + PyErr_SetString(PyExc_TypeError, "first arg expected as string with llcode"); + return NULL; + } + const char* llcode = PyString_AsString(pyllcode); + + // get optional second parameter (fnname) + const char* fnname = NULL; + if (PyTuple_Size(args) > 1) { + PyObject *pyfnname = PyTuple_GetItem(args, 1); + if (!PyString_Check(pyllcode)) { + PyErr_SetString(PyExc_TypeError, "second arg expected as string with functionname"); + return NULL; + } + fnname = PyString_AsString(pyfnname); } + // parse and verify llcode try { - ParseAssemblyString((const char *) llcode, &self->exec->getModule()); + if (fnname) { + // XXX ParseAssemblyString(llcode, &self->exec->getModule()); //redefinition + /*Module* M =*/ ParseAssemblyString(llcode, NULL); + Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname)); + if (fn == NULL) { + PyErr_SetString(PyExc_Exception, "Failed to resolve function to be replaced"); + return NULL; + } + self->exec->recompileAndRelinkFunction(fn); + + // TODO replace fn with whatever ParseAssemblyString made of llcode + + PyErr_SetString(PyExc_Exception, "function replacing not supported yet"); + return NULL; + + } else { + ParseAssemblyString(llcode, &self->exec->getModule()); + } + verifyModule(self->exec->getModule(), ThrowExceptionAction); Py_INCREF(Py_None); return Py_None; @@ -137,7 +181,7 @@ static PyObject *ee_call(PyExecutionEngine *self, PyObject *args) { if (PyTuple_Size(args) == 0) { - PyErr_SetString(PyExc_TypeError, "first arg expected as string"); + PyErr_SetString(PyExc_TypeError, "missing functionname"); return NULL; } @@ -146,7 +190,6 @@ PyErr_SetString(PyExc_TypeError, "first arg expected as string"); return NULL; } - char *fnname = PyString_AsString(pyfnname); try { Added: pypy/dist/pypy/translator/llvm/pyllvm/test/__init__.py ============================================================================== Added: pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/ll_snippet.py Thu Mar 23 16:23:48 2006 @@ -0,0 +1,32 @@ +calc = """int %calc(int %n) { + %tmp.0 = call int %add1(int %n) + ret int %tmp.0 +} +declare int %add1(int)""" + +add1 = """int %add1(int %n) { + %tmp.0 = add int %n, 1 + ret int %tmp.0 +}""" + +add1_version2 = """int %add1(int %n) { + %tmp.0 = add int %n, 100 ;used for testing function replacement + ret int %tmp.0 +}""" + +global_int_a_is_100 = """%a = global int 100""" + +add1_to_global_int_a = """ +int %add1_to_global_int_a() { + %tmp.0 = load int* %a + %tmp.1 = add int %tmp.0, 1 + store int %tmp.1, int* %a + ret int %tmp.1 +}""" + +sub10_from_global_int_a = """int %sub10_from_global_int_a() { + %tmp.0 = load int* %a + %tmp.1 = sub int %tmp.0, 10 + store int %tmp.1, int* %a + ret int %tmp.1 +}""" Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Thu Mar 23 16:23:48 2006 @@ -4,7 +4,12 @@ py.test.skip("llvm not found") from pypy.translator.llvm.pyllvm.build import pyllvm +from pypy.translator.llvm.pyllvm.test import ll_snippet +#XXX When running this with py.test a segfault occurs instead of a nice traceback. +# I don't know currently (and don't care either because I intend to switch to ctypes anyway) +# What I do in this case is find out the failing test (py.test -v) and run that one on +# its own with "py.test -k ". Have fun! def test_execution_engine(): ee = pyllvm.get_ee() @@ -37,13 +42,18 @@ assert returnId > 0 assert name in ('gethellostr', 'hello') assert len(args) == 0 + py.test.raises(Exception, ee.functions, 1) + py.test.raises(Exception, ee.functions, "string") def test_call_parse_once(): ee = get_fresh_ee() ee.parse(codepath.join("hello.s").read()) assert ee.call("hello") == 0 assert ee.call("gethellostr") == "hello world\n" + py.test.raises(Exception, ee.call) + py.test.raises(Exception, ee.call, 1) py.test.raises(Exception, ee.call, "gethellostrx") + py.test.raises(Exception, ee.call, "gethellostrx", 1) py.test.raises(Exception, ee.call, "gethellostr", 1) def test_call_parse_twice(): @@ -53,12 +63,53 @@ ee.parse(codepath.join("addnumbers.s").read()) assert ee.call("add", 10, 32) == 42 assert ee.call("gethellostr") == "hello world\n" + py.test.raises(Exception, ee.parse) + py.test.raises(Exception, ee.parse, 1) + py.test.raises(Exception, ee.parse, "abc") + +def test_call_between_parsed_code(): + """we parse add1 last on purpose to see if the JIT resolves + the function at execution time. Not sure if we really need this + particular feature. It appears that 'calc' requires a forward + declaration to add1 otherwise a segfault will occur!""" + ee = get_fresh_ee() + ee.parse(ll_snippet.calc) + ee.parse(ll_snippet.add1) + assert ee.call("add1", 41) == 42 + assert ee.call("calc", 122) == 123 + +def test_replace_function(): + """similar to test_call_between_parsed_code with additional complexity + because we rebind the add1 function to another version after it the + first version already has been used.""" + py.test.skip("function replacement support in progress") + ee = get_fresh_ee() + ee.parse(ll_snippet.calc) + ee.parse(ll_snippet.add1) + assert ee.call("add1", 41) == 42 + assert ee.call("calc", 122) == 123 + ee.parse(ll_snippet.add1_version2, "add1") + assert ee.call("add1", 42) == 142 + assert ee.call("calc", 142) == 242 -def TODOtest_call_between_parsed_code(): - pass +def test_share_data_between_parsed_code(): + ee = get_fresh_ee() + ee.parse(ll_snippet.global_int_a_is_100) + ee.parse(ll_snippet.add1_to_global_int_a) + ee.parse(ll_snippet.sub10_from_global_int_a) + assert ee.call("add1_to_global_int_a") == 101 + assert ee.call("sub10_from_global_int_a") == 91 + assert ee.call("add1_to_global_int_a") == 92 + assert ee.call("sub10_from_global_int_a") == 82 -def TODOtest_share_data_between_parsed_code(): +def TODOtest_native_code(): #examine JIT generate native (assembly) code pass def TODOtest_delete_function(): pass + +def TODOtest_add_to_function(): + pass + +def TODOtest_optimize_functions(): #add/del/list llvm transformation passes + pass From cfbolz at codespeak.net Thu Mar 23 16:39:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 23 Mar 2006 16:39:59 +0100 (CET) Subject: [pypy-svn] r24884 - in pypy/branch/explicit-exceptions/translator: backendopt c Message-ID: <20060323153959.EEAFE10137@code0.codespeak.net> Author: cfbolz Date: Thu Mar 23 16:39:59 2006 New Revision: 24884 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: (mwh, arre, pedronis) introduce a OneShotInliner to be used by the exceptiontransform. Avoids some of the overdoing of the normal Inliner. Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 16:39:59 2006 @@ -101,19 +101,11 @@ return True return False -class Inliner(object): - def __init__(self, translator, graph, inline_func, inline_guarded_calls=False, +class BaseInliner(object): + def __init__(self, translator, graph, inline_guarded_calls=False, inline_guarded_calls_no_matter_what=False): self.translator = translator self.graph = graph - self.inline_func = inline_func - # to simplify exception matching - join_blocks(graph) - # find callsites *after* joining blocks... - callsites = find_callsites(graph, inline_func) - self.block_to_index = {} - for g, block, i in callsites: - self.block_to_index.setdefault(block, {})[i] = g self.inline_guarded_calls = inline_guarded_calls # if this argument is set, the inliner will happily produce wrong code! # it is used by the exception transformation @@ -223,7 +215,6 @@ newlink.last_exc_value = self.get_new_name(link.last_exc_value) if hasattr(link, 'llexitcase'): newlink.llexitcase = link.llexitcase - return newlink def generate_keepalive(self, vars): keepalive_ops = [] @@ -406,6 +397,29 @@ join_blocks(self.graph) remove_identical_vars(self.graph) +class Inliner(BaseInliner): + def __init__(self, translator, graph, inline_func, inline_guarded_calls=False, + inline_guarded_calls_no_matter_what=False): + BaseInliner.__init__(self, translator, graph, + inline_guarded_calls, inline_guarded_calls_no_matter_what) + self.inline_func = inline_func + # to simplify exception matching + join_blocks(graph) + # find callsites *after* joining blocks... + callsites = find_callsites(graph, inline_func) + self.block_to_index = {} + for g, block, i in callsites: + self.block_to_index.setdefault(block, {})[i] = g + +class OneShotInliner(BaseInliner): + def __init__(self, translator, graph, inline_guarded_calls=False, + inline_guarded_calls_no_matter_what=False): + BaseInliner.__init__(self, translator, graph, + inline_guarded_calls, inline_guarded_calls_no_matter_what) + + def search_for_calls(self, block): + pass + def _inline_function(translator, graph, block, index_operation): inline_func = block.operations[index_operation].args[0].value._obj._callable Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 16:39:59 2006 @@ -1,3 +1,4 @@ +from pypy.translator.simplify import join_blocks from pypy.translator.unsimplify import copyvar, split_block from pypy.translator.backendopt import canraise, inline from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ @@ -90,13 +91,14 @@ from the current graph with a special value (False/-1/-1.0/null). Because of the added exitswitch we need an additional block. """ + join_blocks(graph) for block in list(graph.iterblocks()): #collect the blocks before changing them self.transform_block(graph, block) + self.transform_except_block(graph, graph.exceptblock) checkgraph(graph) def transform_block(self, graph, block): if block is graph.exceptblock: - self.transform_except_block(graph, block) return elif block is graph.returnblock: return @@ -148,10 +150,9 @@ #non-exception case block.exits[0].exitcase = block.exits[0].llexitcase = None # use the dangerous second True flag :-) - inliner = inline.Inliner(self.translator, graph, proxygraph, True, True) - count = inliner.inline_all() - assert count > 0, "didn't inline" - block.exits[0].exitcase = block.exits[0].llexitcase = False + inliner = inline.OneShotInliner(self.translator, graph, True, True) + inliner.inline_once(block, len(block.operations)-1) + #block.exits[0].exitcase = block.exits[0].llexitcase = False def create_proxy_graph(self, op): """ creates a graph which calls the original function, checks for From mwh at codespeak.net Thu Mar 23 16:44:30 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 16:44:30 +0100 (CET) Subject: [pypy-svn] r24885 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323154430.B9DF410137@code0.codespeak.net> Author: mwh Date: Thu Mar 23 16:44:29 2006 New Revision: 24885 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: remove a disablement that i never meant to check in and a small possibly-bug fix Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 16:44:29 2006 @@ -125,10 +125,11 @@ block.exits[0].exitcase = block.exits[0].llexitcase = False if need_exc_matching: assert lastblock.exitswitch == c_last_exception - if 0 and not self.raise_analyzer.can_raise(lastblock.operations[-1]): + if not self.raise_analyzer.can_raise(lastblock.operations[-1]): print "XXX: operation %s cannot raise, but has exception guarding in graph %s" % (lastblock.operations[-1], graph) lastblock.exitswitch = None lastblock.exits = [lastblock.exits[0]] + lastblock.exits[0].exitcase = None else: self.insert_matching(lastblock, graph) From auc at codespeak.net Thu Mar 23 16:57:08 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 23 Mar 2006 16:57:08 +0100 (CET) Subject: [pypy-svn] r24886 - pypy/dist/demo Message-ID: <20060323155708.345331013D@code0.codespeak.net> Author: auc Date: Thu Mar 23 16:57:06 2006 New Revision: 24886 Modified: pypy/dist/demo/producerconsumer.py pypy/dist/demo/uthread.py Log: updated demos Modified: pypy/dist/demo/producerconsumer.py ============================================================================== --- pypy/dist/demo/producerconsumer.py (original) +++ pypy/dist/demo/producerconsumer.py Thu Mar 23 16:57:06 2006 @@ -11,23 +11,23 @@ print "generate", n, limit if n < limit: return (n, generate(n + 1, limit)) - return (None, None) + return None def sum(L, a): print "sum", a - head, Tail = newvar(), newvar() - L == (head, Tail) - if head != None: - return sum(Tail, head + a) - return a + Head, Tail = newvar(), newvar() + unify(L, (Head, Tail)) + if Tail != None: + return sum(Tail, Head + a) + return a + Head print "eager producer consummer" print "before" X = newvar() S = newvar() -S == uthread(sum, X, 0) -X == uthread(generate, 0, 10) +bind(S, uthread(sum, X, 0)) +unify(X, uthread(generate, 0, 10)) print "after" -print S - +assert S == 45 +print S # needs a special treatment Modified: pypy/dist/demo/uthread.py ============================================================================== --- pypy/dist/demo/uthread.py (original) +++ pypy/dist/demo/uthread.py Thu Mar 23 16:57:06 2006 @@ -10,11 +10,11 @@ X = newvar() Y = newvar() -Y == X +bind(Y, X) # aliasing def f(): print "starting" - print is_unbound(X) + print is_free(X) if Y: print "ok" return @@ -22,7 +22,7 @@ return def bind(): - X == 1 + unify(X, 1) uthread(f) print "afterwards" From auc at codespeak.net Thu Mar 23 16:57:51 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 23 Mar 2006 16:57:51 +0100 (CET) Subject: [pypy-svn] r24887 - pypy/dist/pypy/objspace/test Message-ID: <20060323155751.DFD7610141@code0.codespeak.net> Author: auc Date: Thu Mar 23 16:57:50 2006 New Revision: 24887 Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: updated logic objspace test Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Thu Mar 23 16:57:50 2006 @@ -1,31 +1,24 @@ from pypy.conftest import gettestobjspace +class UnificationFailure(Exception): pass + class AppTest_Logic(object): def setup_class(cls): cls.space = gettestobjspace('logic') - def test_simple_bind(self): + def test_bind_var_val(self): X = newvar() assert is_free(X) + assert not is_bound(X) bind(X, 1) assert type(X) == int + assert not is_free(X) assert is_bound(X) assert is_bound(1) - raises(TypeError, bind, 1, 2) - - def test_setitem_bind(self): - x = newvar() - d = {5: x} - d[6] = x - d[7] = [] - d[7].append(x) - y = d[5], d[6], d.values(), d.items() - for x in [d[5], d[6], d[7][0]]: - assert is_free(d[5]) - bind(x, 1) - for x in [d[5], d[6], d[7][0]]: - assert is_bound(d[5]) + # FIXME : propagate proper + # FailureException + raises(Exception, bind, X, 2) def test_bind_to_self(self): X = newvar() @@ -34,45 +27,34 @@ bind(X, 1) assert X == 1 - def test_bind_aliased(self): + def test_unify_to_self(self): + X = newvar() + assert is_free(X) + unify(X, X) + unify(X, 1) + assert X == 1 + + def test_bind_alias(self): X = newvar() Y = newvar() bind(X, Y) + assert is_alias(X, Y) + assert is_alias(X, Y) bind(X, 1) + # what about is_alias, then ? assert X == 1 assert Y == 1 - def test_unbound_unification_long(self): - l = [newvar() for i in range(40)] - for i in range(39): - bind(l[i], l[i + 1]) - bind(l[20], 1) - for i in range(40): - assert l[i] == 1 - - def test_use_unbound_var(self): - X = newvar() - def f(x): - return x + 1 - raises(RuntimeError, f, X) - - - def test_eq_unifies_simple(self): + def test_unify_alias(self): X = newvar() Y = newvar() unify(X, Y) + assert is_alias(X, Y) + assert is_alias(X, Y) unify(X, 1) + # what about is_alias, then ? assert X == 1 - assert is_bound(Y) assert Y == 1 - assert X == Y - - def test_ne_of_unified_unbound_vars(self): - X = newvar() - Y = newvar() - unify(X, Y) - assert X == Y - assert not X != Y def test_cmp(self): X = newvar() @@ -88,50 +70,107 @@ def test_is(self): X = newvar() + Y = newvar() x = 1 assert 1 is 1 assert not(2 is 1) assert X is X + assert X is X bind(X, x) - assert X == 1 + bind(Y, X) + assert X is 1 + assert 1 is X + assert Y is X + assert X is X assert X is x assert not(X is 2) - def test_unify_free(self): - X, Y = newvar(), newvar() + def test_setitem_bind(self): + x = newvar() + d = {5: x} + d[6] = x + d[7] = [] + d[7].append(x) + y = d[5], d[6], d.values(), d.items() + for x in [d[5], d[6], d[7][0]]: + assert is_free(d[5]) + bind(x, 1) + for x in [d[5], d[6], d[7][0]]: + assert is_bound(d[5]) + + def test_unbound_unification_long(self): + l = [newvar() for i in range(40)] + for i in range(39): + bind(l[i], l[i + 1]) + bind(l[20], 1) + for i in range(40): + assert l[i] == 1 + + def test_use_unbound_var(self): + X = newvar() + def f(x): + return x + 1 + raises(RuntimeError, f, X) + + def test_eq_unifies_simple(self): + X = newvar() + Y = newvar() unify(X, Y) - assert X == Y + assert is_alias(Y, X) unify(X, 1) assert X == 1 + assert is_bound(Y) assert Y == 1 - - + assert X is Y + assert X == Y + + def test_ne_of_unified_unbound_vars(self): + X = newvar() + Y = newvar() + unify(X, Y) + assert is_free(X) + assert is_free(Y) + assert is_alias(X, Y) + assert X == Y + assert not X != Y + + def test_unify_list(self): + X = newvar() + x = (newvar(), newvar()) + unify(X, x) + unify(X[1], (newvar(), newvar())) + assert is_bound(X) + assert X == x + assert X[1] == x[1] + unify(X, (1, (2, None))) + assert X == (1, (2, None)) + raises(Exception, unify, X, (1, 2)) class AppTest_LogicThreads(object): def setup_class(cls): cls.space = gettestobjspace('logic') - - def notest_eager_producer_consummer(self): + def test_eager_producer_consummer(self): def generate(n, limit): print "generate", n, limit if n < limit: return (n, generate(n + 1, limit)) - return (None, None) + return None def sum(L, a): print "sum", a - head, Tail = newvar(), newvar() - unify(L, (head, Tail)) - if head != None: - return sum(Tail, head + a) - return a + Head, Tail = newvar(), newvar() + unify(L, (Head, Tail)) + if Tail != None: + return sum(Tail, Head + a) + return a + Head X = newvar() S = newvar() - unify(S, uthread(sum, X, 0)) + + bind(S, uthread(sum, X, 0)) unify(X, uthread(generate, 0, 10)) assert S == 45 From auc at codespeak.net Thu Mar 23 16:58:47 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 23 Mar 2006 16:58:47 +0100 (CET) Subject: [pypy-svn] r24888 - pypy/dist/pypy/objspace Message-ID: <20060323155847.F0E391013D@code0.codespeak.net> Author: auc Date: Thu Mar 23 16:58:45 2006 New Revision: 24888 Modified: pypy/dist/pypy/objspace/logic.py Log: better bind, unify & friends Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Mar 23 16:58:45 2006 @@ -2,6 +2,7 @@ from pypy.interpreter import gateway, baseobjspace, argument from pypy.interpreter.error import OperationError from pypy.rpython.objectmodel import we_are_translated +from pypy.objspace.std.listobject import W_ListObject, W_TupleObject USE_COROUTINES = True HAVE_GREENLETS = True @@ -63,7 +64,7 @@ return blocked def add_to_blocked_byneed(self, w_var, uthread): - print " adding", uthread, "to byneed on", w_var + #print " adding", uthread, "to byneed on", w_var if w_var in self.uthreads_blocked_byneed: blocked = self.uthreads_blocked_byneed[w_var] else: @@ -73,11 +74,11 @@ def pop_blocked_byneed_on(self, w_var): if w_var not in self.uthreads_blocked_byneed: - print " there was nobody to remove for", w_var + #print " there was nobody to remove for", w_var return [] blocked = self.uthreads_blocked_byneed[w_var] del self.uthreads_blocked_byneed[w_var] - print " removing", blocked, "from byneed on", w_var + #print " removing", blocked, "from byneed on", w_var return blocked @@ -119,6 +120,9 @@ def __ne__(self, other): return not (self == other) + def __repr__(self): + return '' % id(self) + def construct_coroutine(): if we_are_translated(): return Coroutine() @@ -151,10 +155,20 @@ argument.Arguments]) +#-- VARIABLE --------------------- + class W_Var(baseobjspace.W_Root, object): def __init__(w_self): - w_self.w_bound_to = None - w_self.w_needed = False + w_self.w_bound_to = None # FIXME : make this a ring + w_self.w_needed = False # is it needed ? + + def __repr__(w_self): + if w_self.w_bound_to: + last = find_last_var_in_chain(w_self) + if last.w_bound_to is not None: + return '<%s@%s>' % (last.w_bound_to, + prettyfy_id(str(id(w_self)))) + return '' % prettyfy_id(str(id(w_self))) def find_last_var_in_chain(w_var): w_curr = w_var @@ -166,7 +180,12 @@ break return w_curr -def wait(space, w_self): +def newvar(space): + return W_Var() +app_newvar = gateway.interp2app(newvar) + + +def wait(space, w_self, w_caller=None): while 1: if not isinstance(w_self, W_Var): return w_self @@ -189,9 +208,12 @@ while schedule_state.have_runnable_threads(): next_coro = schedule_state.pop_runnable_thread() if next_coro.is_alive(): - print " waiter is switching" - next_coro.switch() - print " waiter is back" + #print " waiter is switching" + try: + next_coro.switch() + except: + if w_caller: print "Wait", w_caller + #print " waiter is back" # hope there is a value here now break else: @@ -232,9 +254,9 @@ while schedule_state.have_runnable_threads(): next_coro = schedule_state.pop_runnable_thread() if next_coro.is_alive(): - print " byneed is switching" + #print " byneed is switching" next_coro.switch() - print " byneed is back" + #print " byneed is back" # there might be some need right now break else: @@ -247,46 +269,231 @@ app_wait_needed = gateway.interp2app(wait_needed) -def newvar(space): - return W_Var() -app_newvar = gateway.interp2app(newvar) +#-- PREDICATES -------------------- -def is_unbound(space, w_var): +def is_free(space, w_var): + # XXX make me O(1) if not isinstance(w_var, W_Var): return space.newbool(False) w_last = find_last_var_in_chain(w_var) - return space.newbool(w_last.w_bound_to is None) -app_is_unbound = gateway.interp2app(is_unbound) + return space.newbool(space.is_w(w_last.w_bound_to, None)) +app_is_free = gateway.interp2app(is_free) + +def is_bound(space, w_var): + # XXX make me O(1) + # FIXME (i'm unreliable, where is_free is not) + if space.is_true(is_free(space, w_var)): + return space.newbool(False) + else: + return space.newbool(True) +app_is_bound = gateway.interp2app(is_bound) + +def is_alias(space, w_var1, w_var2): + assert space.is_true(is_free(space, w_var1)) + assert space.is_true(is_free(space, w_var2)) + # w_var2 could be a right-alias of w_var2 + # or the other way around + a = _right_alias(space, w_var1, w_var2) + b = _right_alias(space, w_var2, w_var1) + return space.newbool(a or b) +app_is_alias = gateway.interp2app(is_alias) + +def _right_alias(space, w_var1, w_var2): + """checks wether a var is in the alias chain of another""" + w_curr = w_var1.w_bound_to + while w_curr != None: + if space.is_true(space.is_nb_(w_curr, w_var2)): + return True + w_curr = w_curr.w_bound_to + return False + + +#-- HELPERS ---------------------- + +def deref(space, w_var): + """gets the value of a bound variable + user has to ensure boundness of the var""" + assert isinstance(w_var, W_Var) + # FIXME don't need to walk the chain + return find_last_var_in_chain(w_var).w_bound_to + +def fail(space, w_obj1, w_obj2): + print "can't unify", w_obj1, w_obj2 + raise OperationError(space.w_RuntimeError, + space.wrap("UnificationFailure")) + +def check_and_memoize_pair(space, w_x, w_y): + pass + +def reset_memo(): + pass + +def prettyfy_id(a_str): + l = len(a_str) - 1 + return a_str[l-3:l] + +def aliases(space, w_var): + al = [] + w_curr = w_var + while w_curr is not None: + al.append(w_curr) + w_curr = w_curr.w_bound_to + return al + +def wait_two(space, w_1, w_2): + """waits until one out of two logic variables + becomes bound, then tells which one""" + w_v = newvar(space) + def sleep(space, w_var): + wait(space, w_var) + bind(space, w_var, space.newint(1)) + uthread(sleep, space, w_1) + uthread(sleep, space, w_2) + wait(space, w_c) + if space.is_true(is_free(space, w_2)): + return space.newint(1) + return space.newint(2) + +#-- BIND ----------------------------- def bind(space, w_var, w_obj): - if not isinstance(w_var, W_Var): - raise OperationError(space.w_TypeError, - space.wrap("can only bind logic variable")) - w_last = find_last_var_in_chain(w_var) - if w_last.w_bound_to is not None: - raise OperationError(space.w_TypeError, - space.wrap("can only bind unbound logic variable")) + """1. aliasing of unbound variables + 2. assign unbound var to bound var + 3. assign value to self + """ + print "bind", w_var, w_obj + assert isinstance(w_var, W_Var) if isinstance(w_obj, W_Var): - w_last2 = find_last_var_in_chain(w_obj) - if w_last2.w_bound_to is not None: - w_obj = w_last2 - elif w_last is w_last2: - return space.w_None - else: - w_last.w_bound_to = w_last2 - return + if space.is_true(is_bound(space, w_var)): + if space.is_true(is_bound(space, w_obj)): + unify(space, + deref(space, w_var), + deref(space, w_obj)) + _assign(space, w_obj, deref(space, w_var)) + elif space.is_true(is_bound(space, w_obj)): + _assign(space, w_var, deref(space, w_obj)) + else: # 1. both are unbound + _alias(space, w_var, w_obj) + else: # 3. w_obj is a value + if space.is_true(is_free(space, w_var)): + _assign(space, w_var, w_obj) + unify(space, deref(space, w_var), w_obj) +app_bind = gateway.interp2app(bind) + +def _assign(space, w_var, w_val): w_curr = w_var while w_curr is not None: - assert isinstance(w_curr, W_Var) w_next = w_curr.w_bound_to - w_curr.w_bound_to = w_obj + w_curr.w_bound_to = w_val + # awake the blocked threads + to_awake = schedule_state.pop_blocked_on(w_curr) + for thread in to_awake: + schedule_state.add_to_runnable(thread) + # switch to next w_curr = w_next - if have_uthreads(): - now_unblocked_uthreads = schedule_state.pop_blocked_on(w_last) - for uthread in now_unblocked_uthreads: - schedule_state.add_to_runnable(uthread) return space.w_None -app_bind = gateway.interp2app(bind) + +def _alias(space, w_v1, w_v2): + """appends one var to the alias chain of another + user must ensure freeness of both vars""" + if space.is_true(space.is_nb_(w_v1, w_v2)): + return space.w_None + last = find_last_var_in_chain(w_v1) + last.w_bound_to = w_v2 + return space.w_None + +#-- UNIFY ------------------------- + +def unify(space, w_x, w_y): + print "unify", w_x, w_y + check_and_memoize_pair(space, w_x, w_y) + if not isinstance(w_x, W_Var): + if not isinstance(w_y, W_Var): + # x, y not vars + return _unify_values(space, w_x, w_y) + # x not var, reverse args. order + return unify(space, w_y, w_x) + elif not isinstance(w_y, W_Var): + # x var, y value + return bind(space, w_x, w_y) + # x, y are vars + elif space.is_true(is_bound(space, w_x)) and \ + space.is_true(is_bound(space, w_x)): + return _unify_values(space, + deref(space, w_x), + deref(space, w_y)) + elif space.is_true(is_bound(space, w_x)): + return bind(space, w_y, w_x) + # aliasing x & y ? + else: + return bind(space, w_x, w_y) # aliasing + #XXX: really do what's below : + #return _unify_unbound(space, w_x, w_y) + reset_memo() +app_unify = gateway.interp2app(unify) + + +def _unify_unbound(space, w_x, w_y): + """sleeps until one of the two is bound + then bind the other to its value""" + w_bound = wait_two(space, w_x, w_y) + if space.eq_w(w_bound, space.newint(1)): + return bind(space, w_y, w_x) + return bind(space, w_x, w_y) + +def _unify_values(space, w_v1, w_v2): + print " unify values", w_v1, w_v2 + # unify object of the same type ... FIXME + if not space.is_w(space.type(w_v1), + space.type(w_v2)): + fail(space, w_v1, w_v2) + # ... elements of a list/tuple ... + if isinstance(w_v1, W_ListObject) or \ + isinstance(w_v1, W_TupleObject): + _unify_iterables(space, w_v1, w_v2) + else: + # ... token equality + if not space.eq_w(w_v1, w_v2): + fail(space, w_v1, w_v2) + return space.w_None + +def _unify_iterables(space, w_i1, w_i2): + print " unify iterables", w_i1, w_i2 + # assert lengths + if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): + fail(space, w_i1, w_i2) + # co-iterate and unify elts + idx, top = (-1, space.int_w(space.len(w_i1))-1) + while idx < top: + idx += 1 + w_xi = space.getitem(w_i1, space.newint(idx)) + w_yi = space.getitem(w_i2, space.newint(idx)) + if space.is_true(space.is_nb_(w_xi, w_yi)): + continue + unify(space, w_xi, w_yi) + +# multimethod version of unify +## def unify__W_Var_W_Var(space, w_v1, w_v2): +## return bind(space, w_v1, w_v2) + +## def unify__W_Var_W_ObjectObject(space, w_var, w_obj): +## return bind(space, w_v1, w_obj) + +## def unify_W_ObjectObject_W_Var(space, w_obj, w_var): +## return unify__W_Var_W_ObjectObject(space, w_var, w_obj) + +## def unify__W_ObjectObject_W_ObjectObject(space, w_obj1, w_obj2): +## if not space.eq(w_obj1, w_obj2): +## fail(space, w_obj1, w_obj2) +## return space.w_None + +## def unify__W_ListObject_W_ListObject(space, w_list1, w_list2): +## if len(w_list1) != len(w_list2): # .wrappeditems ? +## fail(space, w_list1, w_list2) +## for e1, e2 in zip(w_list1, w_list2): # .wrappeditems ? +## space.wrap(unify(space, e1, e2)) # ... ? + +# questions : how to make this available to applevel ? # __________________________________________________________________________ @@ -326,56 +533,51 @@ setup() del setup -def isoreqproxy(space, parentfn): - def isoreq(w_obj1, w_obj2): - if space.is_true(is_unbound(space, w_obj1)): - bind(space, w_obj1, w_obj2) - return space.w_True - if space.is_true(is_unbound(space, w_obj2)): - bind(space, w_obj2, w_obj1) - return space.w_True +def eqproxy(space, parentfn): + def eq(w_obj1, w_obj2): + if space.is_true(space.is_nb_(w_obj1, w_obj2)): + return space.newbool(True) + if space.is_true(is_free(space, w_obj1)): + if space.is_true(is_free(space, w_obj2)): + if space.is_true(is_alias(space, w_obj1, w_obj2)): + return space.newbool(True) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) - return isoreq + return eq + +def isproxy(space, parentfn): + def is_(w_obj1, w_obj2): + if space.is_true(space.is_nb_(w_obj1, w_obj2)): + return space.newbool(True) + return parentfn(wait(space, w_obj1), wait(space, w_obj2)) + return is_ def cmpproxy(space, parentfn): def cmp(w_obj1, w_obj2): - if space.is_true(is_unbound(space, w_obj1)): - bind(space, w_obj1, w_obj2) - return space.wrap(0) - if space.is_true(is_unbound(space, w_obj2)): - bind(space, w_obj2, w_obj1) - return space.wrap(0) + if space.is_true(space.is_nb_(w_obj1, w_obj2)): + return space.newbool(0) + if space.is_true(is_free(space, w_obj1)): + if space.is_true(is_free(space, w_obj2)): + if space.is_true(is_alias(space, w_obj1, w_obj2)): + return space.newbool(0) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return cmp def neproxy(space, parentfn): def ne(w_obj1, w_obj2): - if (isinstance(w_obj1, W_Var) and isinstance(w_obj2, W_Var) and - space.is_true(is_unbound(space, w_obj1)) and - space.is_true(is_unbound(space, w_obj2))): + if space.is_true(is_free(space, w_obj1)) and \ + space.is_true(is_free(space, w_obj2)): w_var1 = find_last_var_in_chain(w_obj1) w_var2 = find_last_var_in_chain(w_obj2) - if w_var1 is w_var2: + if w_var1 is w_var2: # hmmm return space.w_False return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return ne -def is_wproxy(space, parentfn): - def is_w(w_obj1, w_obj2): - if space.is_true(is_unbound(space, w_obj1)): - bind(space, w_obj1, w_obj2) - return True - if space.is_true(is_unbound(space, w_obj2)): - bind(space, w_obj2, w_obj1) - return True - return parentfn(wait(space, w_obj1), wait(space, w_obj2)) - return is_w - def proxymaker(space, opname, parentfn): - if opname == "is_w": - return is_wproxy(space, parentfn) - if opname == "eq" or opname == "is_": - return isoreqproxy(space, parentfn) + if opname == "eq": + return eqproxy(space, parentfn) + if opname == "is_": # FIXME : is_, is_w ? + return isproxy(space, parentfn) if opname == "ne": return neproxy(space, parentfn) if opname == "cmp": @@ -385,7 +587,7 @@ proxy = None elif nb_args == 1: def proxy(w1, *extra): - w1 = wait(space, w1) + w1 = wait(space, w1, parentfn) return parentfn(w1, *extra) elif nb_args == 2: def proxy(w1, w2, *extra): @@ -403,17 +605,25 @@ (opname, nb_args)) return proxy + def Space(*args, **kwds): # for now, always make up a wrapped StdObjSpace from pypy.objspace import std space = std.Space(*args, **kwds) + space.is_nb_ = space.is_ # capture the original is_ op patch_space_in_place(space, 'logic', proxymaker) space.setitem(space.builtin.w_dict, space.wrap('newvar'), space.wrap(app_newvar)) - space.setitem(space.builtin.w_dict, space.wrap('is_unbound'), - space.wrap(app_is_unbound)) + space.setitem(space.builtin.w_dict, space.wrap('is_free'), + space.wrap(app_is_free)) + space.setitem(space.builtin.w_dict, space.wrap('is_bound'), + space.wrap(app_is_bound)) + space.setitem(space.builtin.w_dict, space.wrap('is_alias'), + space.wrap(app_is_alias)) space.setitem(space.builtin.w_dict, space.wrap('bind'), space.wrap(app_bind)) + space.setitem(space.builtin.w_dict, space.wrap('unify'), + space.wrap(app_unify)) if USE_COROUTINES: import os def exitfunc(): From ale at codespeak.net Thu Mar 23 17:20:28 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Mar 2006 17:20:28 +0100 (CET) Subject: [pypy-svn] r24891 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060323162028.5059E10137@code0.codespeak.net> Author: ale Date: Thu Mar 23 17:20:27 2006 New Revision: 24891 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: A little update Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Thu Mar 23 17:20:27 2006 @@ -13,7 +13,7 @@ Eric van Riet Paap Jacob Hall?n Laura Creighton -Anders Lehmann +Anders Lehmann 23/4 - 1/5 ? Niklaus Haldimann Anders Chrigstr?m Samuele Pedroni From mwh at codespeak.net Thu Mar 23 18:06:58 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 18:06:58 +0100 (CET) Subject: [pypy-svn] r24892 - pypy/extradoc/minute Message-ID: <20060323170658.BB8DE10137@code0.codespeak.net> Author: mwh Date: Thu Mar 23 18:06:57 2006 New Revision: 24892 Added: pypy/extradoc/minute/pypy-sync-2006-03-23.txt (contents, props changed) Log: version 0.1 of the minutes of today's meeting Added: pypy/extradoc/minute/pypy-sync-2006-03-23.txt ============================================================================== --- (empty file) +++ pypy/extradoc/minute/pypy-sync-2006-03-23.txt Thu Mar 23 18:06:57 2006 @@ -0,0 +1,283 @@ +============================================= +pypy-sync developer meeting 23rd March 2006 +============================================= + + +Attendees: + - Anders C. + - Anders L. + - Aurelien Campeas + - Carl Friedrich + - Christian + - Holger + - Michael (minutes) + - Nik + - Richard + - Samuele + +Summary +======= + + - activity reports + + See `the log`_ below. + + - status of tokyo sprint + + Samuele reported that the sprint announcement is nearly ready and + should go out soon. Planning is hampered by the fact that we don't + really know how many Japanese participants there will be there, and + it's not even certain how many PyPy-ers will be travelling over. + This last bit we can actually do something about, so: + + If you're in `extradoc/sprintinfo/tokyo/people.txt`_, could you + please update that file with your real intentions. + + .. _`extradoc/sprintinfo/tokyo/people.txt`: http://codespeak.net/svn/pypy/`extradoc/sprintinfo/tokyo/people.txt` + + - goals of the 0.9 release + + We agreed to relase 0.9 fairly soon, probably in the second week of + June. The main focus of the release will be "WP07 stuff" in EU + jargon, which is to say stackless features (including tasklet + pickling), but the release should also include previews of the + optimization/JIT/logic work. Sorting out the details of this was + delegated to the Leysin sprinters. + + - status and work planning for the next few weeks + + Basically we all know what we're working on at the moment + (logic/GC/JIT) and we'll continue to work on these things as much + as we're able to (holidays and bureaucracy permitting) until and + during Leysin. + + - targetting non-Python conferences + + Fairly recently, we've missed the paper submission deadlines for + OOPSLA and OSCON. We need to get a handle on which conferences + we're targetting sufficiently far in advance that we actually make + these deadlines. The poster deadline for OOPSLA is 30th June, we + should try to make that... + + - moderation of the next #pypy-sync meeting + + As I am going to be on holiday, Anders Lehmann will moderate the + pypy-sync meeting next week. + +.. _`the log`: + +Complete Log +============ + +This is the full log of the meeting:: + + [16:02] stakkars: hi + [16:03] hpk: hi christian! + [16:03] hpk: hi all + [16:03] aleale: hi + [16:04] rxe joined the chat room. + [16:04] cfbolz: should we maybe start with activivty lines? + [16:04] cfbolz: hi richard! + [16:04] rxe: Hi all! + [16:05] stakkars: ok I'll start + [16:06] hpk: ok, i guess i can take over + [16:06] stakkars: DONE: stackless contexts (little), extension building + [16:06] hpk: i mailed about the topcis earlier anyway + [16:06] stakkars: NEXT: the raymond module :-) + [16:06] stakkars: BLOCK: five lines of docs of current state and scope of gctransform would have saved 2 days + [16:07] auc: LAST : work on logic objspace + [16:07] auc: NEXT : idem + [16:07] auc: BLOCKER : possibly greenlet stuff + [16:07] nikh: LAST: gensqueak + [16:07] nikh: NEXT: gensqueak: tuples, maybe other data structures + [16:07] nikh: BLOCKERS: none + [16:07] mwh: hello + [16:07] cfbolz: LAST: GC work + [16:07] cfbolz: NEXT: more GC work, personal stuff + [16:07] cfbolz: BLOCKERS: personal issues + [16:07] hpk: LAST: US trip (hp/py.test consulting), amendment-4 and (TB) communications, codespeak problems + [16:07] hpk: NEXT: non-pypy, still a bit of amendment work + [16:07] hpk: BLOCKERS: exhaustion or something + [16:07] mwh: sorry for being late... + [16:07] aleale: PREV: working on making the official OWL test pass + [16:07] aleale: NEXT: more of the above + [16:07] aleale: BLOCKERS: - + [16:07] pedronis: LAST: make ootype more static, some jit work, helper GC stuff + [16:07] pedronis: NEXT: more helping GC stuff, jit work, leysin sprint, + [16:07] pedronis: BLOCKERS: - + [16:08] mwh: i have an activity report from eric: + [16:08] arre: PREV: Non-PyPy-work, some JIT-work, travel-planing + [16:08] arre: NEXT: More JIT and Leysin-sprint + [16:08] arre: BLOCKERS: - + [16:08] mwh: LAST: got LLVM JIT codegenerator working with rgenop.py graphs + [16:08] mwh: NEXT: extend pyllvm, maybe convert it to using ctypes + [16:08] mwh: BLOCKERS: ctypes misses C API for LLVM + [16:08] mwh: for myself: + [16:08] mwh: LAST: c/exceptions/gc hacking + [16:08] mwh: NEXT: holiday + [16:08] mwh: BLOCKERS: - + [16:09] hpk: goden, xorAxAx: anything? + [16:09] cfbolz: rxe: you? + [16:09] hpk: all others except the pybot delivered i think + [16:09] rxe: no :-( + [16:10] hpk: then next topic? + [16:10] arigo joined the chat room. + [16:10] mwh: so i don't see any blockers that can be resolved here + [16:11] cfbolz: yes + [16:11] cfbolz: hi armin! + [16:11] arigo: joined "pypy-snc" by mistake + [16:11] mwh: heh + [16:11] stakkars: moin + [16:11] mwh: first topic is: "status of tokyo sprint" + [16:12] hpk: i haven't dealt with this since a number of weeks - do you have news, samuele? + [16:12] pedronis: we got the logistic information, and an announcement has been drafted + [16:12] mwh: my impression is that things are under control but as i'm not going i haven't really been paying attention + [16:12] pedronis: we need to decide what are the technical goals/topics for it + [16:12] pedronis: to finish it and send it out + [16:12] pedronis: should happen before the weekend + [16:13] pedronis: it's of course a bit unclear what to propose + [16:13] hpk: any info about the participants (number/likely interests)? + [16:13] pedronis: because things are so in flux in general right now + [16:13] pedronis: there may be 20 japanese + [16:13] hpk: i remember that bea/me tried to extract some information and one feedback was "might be up to 20 people" but it didn't get more concrete i think + [16:13] pedronis: form our side it would nice + [16:13] pedronis: if people updated people.txt + [16:14] pedronis: with their real intententions + [16:14] hpk: yip, currently there are 9 people + [16:14] pedronis: do know how many of "us" are really going to be there + [16:15] arre: Jacob and Laura are not certain they can make it. + [16:15] hpk: nikh, aleale, stakkars: you plan to go as listed in the people.txt? + [16:15] nikh: yep, i will come + [16:15] aleale: yep + [16:15] stakkars: It is not clear because something else is going on. I need to add another subtopic, just to increase confusion: + [16:16] stakkars: EWT is considering to do a sprint in Iceland, late May. They will sponsor it.!! + [16:16] auc: EWT ? + [16:16] hpk: stakkars: i think we have lots of topic already, can it wait until next week? + [16:16] stakkars: a company which I'm consulting for, interested in PyPy + [16:16] CyDefect joined the chat room. + [16:17] mwh: yes, this is a very packed meeting + [16:17] auc: stakkars: but what EWT does stand for ? (if not indiscrete) + [16:17] mwh: stakkars: is this supposed to be public information yet? + [16:17] stakkars: hpk: I expected this to come. I only wanted to inject the information now, so people get a picture about the schedule + [16:17] CyDefect is now known as Gromit. + [16:18] hpk: pedronis: can you trigger bea to re-check with the japanase people and try to get the announcement finished by the weekend? + [16:18] mwh: i'd like to move along pretty sharpish, so any concrete things to be done about tokyo ? + [16:18] hpk: stakkars: sure, it's great - you can also post it to pypy-dev and we can discuss it there e.g. + [16:18] mwh: like hpk just said + [16:18] aleale: auc : see http://ewtcareers.com/ + [16:18] pedronis: hpk: that's the plan, although I think we will get more feedback form japanese side when the announcement is out + [16:19] auc: aleale: thanks + [16:19] stakkars: mwh: not exactly, they are discussing, it will be organized by STeve Holden, I will talk to him today. I just needed to say this now, just in case it is a bad idea + [16:19] mwh: stakkars: ok + [16:19] mwh: i won't make a song and dance about it in the minutes then + [16:19] mwh: --------- + [16:19] mwh: - goals of the 0.9 release + [16:19] mwh: i'm guessing this is mostly going to be a stackless/gc/wp07 release + [16:20] mwh: maybe logicobjectspace too? + [16:20] cfbolz: gc/stackless/wp07: definitively + [16:20] auc: mwh: depends on the timeframe + [16:20] hpk: also it should include early or progressed optimization works + [16:20] mwh: auc: to be released late may/early june + [16:20] hpk: like JIT and things on object level (WP06 in EU jargon) + [16:20] auc: mwh: that could be ok + [16:21] auc: mwh: but not sure about *all* the constraint solving stuff + [16:21] cfbolz: of course not + [16:21] mwh: auc: sure + [16:21] mwh: but some kind of meaningful preview would be cool + [16:21] hpk: timeframe is June ... mid June like around 15th? + [16:21] mwh: hpk: don't know if the JIT is going to be releasable for this release + [16:22] mwh: would be cool if it was, of course + [16:22] hpk: mwh: "include early or progressed optimization works" leaves this open + [16:22] mwh: hpk: well, yes + [16:22] hpk: having some results on the toy language should be feasible + [16:23] cfbolz: we should, at least + [16:23] mwh: i guess + [16:23] cfbolz: next topic? + [16:23] mwh: anyway, we don't really have time for that discussion + [16:23] mwh: ------------- + [16:23] mwh: - status and work planning for the next few weeks + [16:24] hpk: mwh: we can also delegate + [16:24] mwh: hpk: true + [16:24] hpk: in this case i'd say we agree on the June timeframe and mabye set the 15th June + [16:24] mwh: hpk: do we want to do that? + [16:24] hpk: and delegate to the Leysin group to define the scope and contents of the release + [16:24] hpk: if everybody is fine with that + [16:24] mwh: maybe a little earlier? + [16:24] arre: Ok with me. + [16:24] mwh: (no real reason) + [16:24] pedronis: Ok + [16:24] mwh: but fine with the delegation + [16:24] stakkars: yup + [16:25] hpk: ok, we can still adapt (10th june might be sensible as well) + [16:25] mwh: for my part i can pretty accurately estimate how much work i'm going to do between now and leysin: none, as i go on holiday tomorrow + [16:25] mwh: (late tomorrow, but...) + [16:25] hpk: until leysin i will not be invovled much either except for amendment-4 and some non-core stuff, i am afraid + [16:26] mwh: i'm guessing leysin will be jit/gc stuff + [16:26] mwh: tasklet pickling? + [16:26] cfbolz: yes! + [16:26] hpk: mwh: and whatever we determine worthwhile + [16:26] mwh: more wp09 stuff + [16:26] stakkars: I hope I can make it to Leysin. That's a tough one + [16:26] mwh: hpk: well, yes... + [16:26] mwh: hpk: it was you that suggested this as a #pypy-sync topic :) + [16:27] hpk: yes, what do you imply? + [16:28] mwh: just that if you wanted to talk about it here, that you had some thing more to say than "and whatever we determine worthwhile" + [16:28] stedi67 joined the chat room. + [16:28] mwh: that hardly requires discussion... + [16:28] hpk: mwh: that was refering to Leysin + [16:28] mwh: no biggie + [16:28] mwh: ok + [16:28] hpk: and to the JIG/GC mentioning + [16:28] mwh: so, last-but-one topic: + [16:28] mwh: - targetting non-Python conferences + [16:28] mwh: the oopsla deadline just sailed past us + [16:29] mwh: how do we stop this happening again? + [16:29] hpk: and what non-python conferences are left? + [16:29] auc: what about ECOOP ? + [16:29] pedronis: well, the idea is still to target the dynamic lang workshop at OOPSLA + [16:29] mwh: a good start would be to get conference and deadlines on to the pypy calendar + [16:29] pedronis: that has a later and different deadline than the main track + [16:29] mwh: but i don't really know when they are + [16:30] mwh: pedronis: ah hah + [16:30] hpk: arigo, pedronis: i think we once said that you two would keep an eye on those conferences - can you try to list deadlines and identify worthwhile conferences from your perspective? + [16:30] cfbolz: pedronis: ah, cool! + [16:30] mwh: maybe i should mail pypy-dev and ask for some dates? + [16:30] pedronis: most of the conferences had deadlines + [16:30] pedronis: at the end of last year + [16:30] pedronis: (nov dec) + [16:31] mwh: argh + [16:31] hpk: ECOOP has passed as well + [16:32] hpk: pedronis: should we mail Roel to ask him about worthwhile conferences (explaining that we missed the deadlines nov/dec 2005)? + [16:32] mwh: points at the clock + [16:33] mwh: who's going to moderate next week? + [16:33] hpk: mwh: we started 17:05 or 07 or so + [16:33] mwh: hpk: i know + [16:33] hpk: will probably (but not certainly) be on travel during that time next week + [16:33] pedronis: bah, it seems that for this year dyn lang workshop + [16:33] pedronis: they have only invited talks + [16:34] cfbolz: pedronis: wasn't that what roel said? + [16:34] pedronis: I forgot then + [16:34] pedronis: too many things + [16:34] cfbolz: yes :-( + [16:34] cfbolz: pedronis: I guess we could still talk to him again + [16:35] hpk: cfbolz: do you feel like asking him? I can review any mails + [16:35] auc: maybe i'm just dense ... i can see submission deadlines for ecoop 2006 workshops around 1st April ... (2006) + [16:35] hpk: didn't look at the workshops + [16:35] cfbolz: hpk: sorry, not really :-( + [16:36] pedronis: for oopsla what's left are posters + [16:36] mwh: points at the clock, again + [16:36] mwh: we can continue this discussion in #pypy + [16:37] hpk: ok + [16:37] mwh: who is going to moderate next week? + [16:37] auc: http://icooolps.loria.fr/ + [16:37] mwh: it's not hpk (probably) and it's not me + [16:37] auc: http://prog.vub.ac.be/~wdmeuter/RDL06/ + [16:37] auc: (roel is part of this one) + [16:37] aleale: I can do the moderation + [16:38] cfbolz: ok, see you all next week then + [16:38] hpk: see you + [16:38] rxe: Bye! + [16:38] mwh: aleale: thank you + [16:38] nikh: bye bye + [16:38] mwh: meeting over + [16:38] mwh: thanks for coming, sorry for the late start (again...) From mwh at codespeak.net Thu Mar 23 18:08:04 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 18:08:04 +0100 (CET) Subject: [pypy-svn] r24893 - pypy/extradoc/minute Message-ID: <20060323170804.A8DE010137@code0.codespeak.net> Author: mwh Date: Thu Mar 23 18:08:03 2006 New Revision: 24893 Modified: pypy/extradoc/minute/pypy-sync-2006-03-23.txt Log: remove junk from url Modified: pypy/extradoc/minute/pypy-sync-2006-03-23.txt ============================================================================== --- pypy/extradoc/minute/pypy-sync-2006-03-23.txt (original) +++ pypy/extradoc/minute/pypy-sync-2006-03-23.txt Thu Mar 23 18:08:03 2006 @@ -33,7 +33,7 @@ If you're in `extradoc/sprintinfo/tokyo/people.txt`_, could you please update that file with your real intentions. - .. _`extradoc/sprintinfo/tokyo/people.txt`: http://codespeak.net/svn/pypy/`extradoc/sprintinfo/tokyo/people.txt` + .. _`extradoc/sprintinfo/tokyo/people.txt`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt - goals of the 0.9 release From mwh at codespeak.net Thu Mar 23 18:15:47 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 18:15:47 +0100 (CET) Subject: [pypy-svn] r24894 - pypy/extradoc/minute Message-ID: <20060323171547.1086010137@code0.codespeak.net> Author: mwh Date: Thu Mar 23 18:15:46 2006 New Revision: 24894 Modified: pypy/extradoc/minute/pypy-sync-2006-03-23.txt Log: armin was here; fold a long line Modified: pypy/extradoc/minute/pypy-sync-2006-03-23.txt ============================================================================== --- pypy/extradoc/minute/pypy-sync-2006-03-23.txt (original) +++ pypy/extradoc/minute/pypy-sync-2006-03-23.txt Thu Mar 23 18:15:46 2006 @@ -6,6 +6,7 @@ Attendees: - Anders C. - Anders L. + - Armin - Aurelien Campeas - Carl Friedrich - Christian @@ -33,7 +34,8 @@ If you're in `extradoc/sprintinfo/tokyo/people.txt`_, could you please update that file with your real intentions. - .. _`extradoc/sprintinfo/tokyo/people.txt`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt + .. _`extradoc/sprintinfo/tokyo/people.txt`: + http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt - goals of the 0.9 release From arigo at codespeak.net Thu Mar 23 18:17:58 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Mar 2006 18:17:58 +0100 (CET) Subject: [pypy-svn] r24895 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060323171758.EB6B510137@code0.codespeak.net> Author: arigo Date: Thu Mar 23 18:17:57 2006 New Revision: 24895 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: I'm signing off for Tokyo. Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Thu Mar 23 18:17:57 2006 @@ -24,6 +24,7 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== +Armin Rigo not coming Ludovic Aubry Adrien Di Mascio Laura Creighton From pedronis at codespeak.net Thu Mar 23 18:18:22 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 18:18:22 +0100 (CET) Subject: [pypy-svn] r24896 - pypy/branch/explicit-exceptions/translator/backendopt Message-ID: <20060323171822.AAF601013F@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 18:18:21 2006 New Revision: 24896 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py Log: bad move Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 18:18:21 2006 @@ -215,6 +215,7 @@ newlink.last_exc_value = self.get_new_name(link.last_exc_value) if hasattr(link, 'llexitcase'): newlink.llexitcase = link.llexitcase + return newlink def generate_keepalive(self, vars): keepalive_ops = [] From pedronis at codespeak.net Thu Mar 23 18:36:45 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 18:36:45 +0100 (CET) Subject: [pypy-svn] r24897 - in pypy/branch/explicit-exceptions/translator: . backendopt c Message-ID: <20060323173645.078CC1013D@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 18:36:44 2006 New Revision: 24897 Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py pypy/branch/explicit-exceptions/translator/simplify.py Log: cleanup graph on which inlining has been performed as appropriate. Add cleanup_graph helper in simplify.py . Modified: pypy/branch/explicit-exceptions/translator/backendopt/inline.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/backendopt/inline.py (original) +++ pypy/branch/explicit-exceptions/translator/backendopt/inline.py Thu Mar 23 18:36:44 2006 @@ -1,6 +1,6 @@ import sys -from pypy.translator.simplify import eliminate_empty_blocks, join_blocks -from pypy.translator.simplify import remove_identical_vars, get_graph +from pypy.translator.simplify import join_blocks, cleanup_graph +from pypy.translator.simplify import get_graph from pypy.translator.unsimplify import copyvar, split_block from pypy.translator.backendopt import canraise from pypy.objspace.flow.model import Variable, Constant, Block, Link @@ -393,10 +393,8 @@ """ cleaning up -- makes sense to be done after inlining, because the inliner inserted quite some empty blocks and blocks that can be joined. """ - checkgraph(self.graph) - eliminate_empty_blocks(self.graph) - join_blocks(self.graph) - remove_identical_vars(self.graph) + cleanup_graph(self.graph) + class Inliner(BaseInliner): def __init__(self, translator, graph, inline_func, inline_guarded_calls=False, Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 18:36:44 2006 @@ -1,4 +1,4 @@ -from pypy.translator.simplify import join_blocks +from pypy.translator.simplify import join_blocks, cleanup_graph from pypy.translator.unsimplify import copyvar, split_block from pypy.translator.backendopt import canraise, inline from pypy.objspace.flow.model import Block, Constant, Variable, Link, \ @@ -95,7 +95,7 @@ for block in list(graph.iterblocks()): #collect the blocks before changing them self.transform_block(graph, block) self.transform_except_block(graph, graph.exceptblock) - checkgraph(graph) + cleanup_graph(graph) def transform_block(self, graph, block): if block is graph.exceptblock: Modified: pypy/branch/explicit-exceptions/translator/simplify.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/simplify.py (original) +++ pypy/branch/explicit-exceptions/translator/simplify.py Thu Mar 23 18:36:44 2006 @@ -720,3 +720,10 @@ pass_(graph) checkgraph(graph) +def cleanup_graph(graph): + checkgraph(graph) + eliminate_empty_blocks(graph) + join_blocks(graph) + remove_identical_vars(graph) + checkgraph(graph) + From mwh at codespeak.net Thu Mar 23 18:40:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Mar 2006 18:40:15 +0100 (CET) Subject: [pypy-svn] r24898 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323174015.70FD61013D@code0.codespeak.net> Author: mwh Date: Thu Mar 23 18:40:14 2006 New Revision: 24898 Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py Log: convert rpython exceptions to cpython exceptions in wrapper functions. now all test_exceptiontransform.py tests passes, but i'm getting strange segfaults in test_newgc... Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Thu Mar 23 18:40:14 2006 @@ -188,6 +188,12 @@ if len(block.exits) == 0: assert len(block.inputargs) == 1 # regular return block + if self.cpython_exc: + assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr + yield 'if (RPyExceptionOccurred()) {' + yield '\tRPyConvertExceptionToCPython(rpython_exc_value);' + yield '\treturn NULL;' + yield '}' retval = self.expr(block.inputargs[0]) yield 'return %s;' % retval continue From pedronis at codespeak.net Thu Mar 23 19:17:48 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 19:17:48 +0100 (CET) Subject: [pypy-svn] r24900 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323181748.7AD8E1013D@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 19:17:42 2006 New Revision: 24900 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: (arre, pedronis) XXX note about what needs fixing. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 19:17:42 2006 @@ -74,6 +74,8 @@ RPYEXC_RAISE = lltype.FuncType([self.exc_data.lltype_of_exception_type, self.exc_data.lltype_of_exception_value], lltype.Void) + # XXX cannot really be called as a normal function, it wants to steal + # the argument reference away, so those should not be pop_alive (decrefed) self.rpyexc_raise_ptr = Constant(lltype.functionptr( RPYEXC_RAISE, "RPyRaiseException", external="C", neverraises=True, _callable=rpyexc_raise), From pedronis at codespeak.net Thu Mar 23 19:42:42 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 19:42:42 +0100 (CET) Subject: [pypy-svn] r24901 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323184242.95DB510135@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 19:42:41 2006 New Revision: 24901 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: typo. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Thu Mar 23 19:42:41 2006 @@ -75,7 +75,7 @@ self.exc_data.lltype_of_exception_value], lltype.Void) # XXX cannot really be called as a normal function, it wants to steal - # the argument reference away, so those should not be pop_alive (decrefed) + # the argument references away, so those should not be pop_alive (decrefed) self.rpyexc_raise_ptr = Constant(lltype.functionptr( RPYEXC_RAISE, "RPyRaiseException", external="C", neverraises=True, _callable=rpyexc_raise), From tismer at codespeak.net Thu Mar 23 22:55:00 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 23 Mar 2006 22:55:00 +0100 (CET) Subject: [pypy-svn] r24914 - pypy/dist/pypy/translator/c Message-ID: <20060323215500.424B610142@code0.codespeak.net> Author: tismer Date: Thu Mar 23 22:54:38 2006 New Revision: 24914 Modified: pypy/dist/pypy/translator/c/funcgen.py Log: enabled disabling old increfs, 'cause it crashes my code, only. Adding a test, now Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Thu Mar 23 22:54:38 2006 @@ -12,7 +12,7 @@ LOCALVAR = 'l_%s' # I'm not absolutely sure, so just in case: -NEED_OLD_EXTRA_REFS = True # oupps seems to be +NEED_OLD_EXTRA_REFS = False class FunctionCodeGenerator(object): """ From antocuni at codespeak.net Thu Mar 23 23:08:59 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 23 Mar 2006 23:08:59 +0100 (CET) Subject: [pypy-svn] r24918 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060323220859.3251F10153@code0.codespeak.net> Author: antocuni Date: Thu Mar 23 23:07:56 2006 New Revision: 24918 Added: pypy/dist/pypy/translator/cli/opcodes.py (contents, props changed) pypy/dist/pypy/translator/cli/test/test_op.py (contents, props changed) Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/cli/test/compile.py pypy/dist/pypy/translator/cli/test/runtest.py pypy/dist/pypy/translator/cli/test/test_flow.py Log: Moved opcodes mapping from function.py to the new opcodes.py. Added some new opcodes to the mapping Added some tests Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Thu Mar 23 23:07:56 2006 @@ -18,7 +18,8 @@ } _cts_to_ilasm = { - 'int32': 'i4' + 'int32': 'i4', + 'bool': 'i4' } def lltype_to_cts(t): @@ -48,7 +49,11 @@ return lltype_to_cts(const.concretetype), const.value def llconst_to_ilasm(const): - return lltype_to_ilasm(const.concretetype), const.value + ilasm_type = lltype_to_ilasm(const.concretetype) + if const.concretetype is Bool: + return ilasm_type, int(const.value) + else: + return ilasm_type, const.value def graph_to_signature(graph): ret_type, ret_var = llvar_to_cts(graph.getreturnvar()) Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Thu Mar 23 23:07:56 2006 @@ -2,6 +2,7 @@ from pypy.rpython.lltypesystem.lltype import Void from pypy.translator.cli import conftest from pypy.translator.cli import cts +from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs from pypy.tool.ansi_print import ansi_log import py @@ -9,16 +10,6 @@ py.log.setconsumer("cli", ansi_log) -DoNothing = object() -opcodes = { - 'int_add': 'add', - 'int_sub': 'sub', - 'int_gt': 'cgt', - 'int_lt': 'clt', - 'int_is_true': DoNothing, - 'same_as': DoNothing, # TODO: does same_as really do nothing else than renaming? - } - class Node(object): def get_name(self): pass @@ -77,6 +68,14 @@ self._push(block.exitswitch) self.ilasm.branch_if(link.exitcase, target_label) + # add a block that will never be executed, just to please the + # .NET runtime that seems to need a return statement at the + # end of the function + if returntype != 'void': + self.ilasm.opcode('ldc.i4.0') + + self.ilasm.opcode('ret') + ilasm.end_function() def _set_locals(self): @@ -132,12 +131,11 @@ opname = op.opname cli_opcode = opcodes.get(opname, None) - if cli_opcode is DoNothing: - # simply rename the variable + if cli_opcode is DoNothing: # simply rename the variable self._push(op.args[0]) self._store(op.result) elif cli_opcode is not None: - self._simple_op(cli_opcode, op) + self._render_cli_opcode(cli_opcode, op) elif opname == 'direct_call': self._call(op) else: @@ -147,6 +145,22 @@ else: assert False, 'Unknown opcode: %s ' % op + def _render_cli_opcode(self, cli_opcode, op): + if type(cli_opcode) is str: + instructions = [PushArgs, cli_opcode] + else: + instructions = cli_opcode + + for instr in instructions: + if instr is PushArgs: + for arg in op.args: + self._push(arg) + else: + self.ilasm.opcode(instr) + + self._store(op.result) + + def _call(self, op): func_name = cts.graph_to_signature(op.args[0].value.graph) @@ -156,23 +170,13 @@ self.ilasm.call(func_name) self._store(op.result) - - - def _simple_op(self, cli_opcode, op): - # push arg on stack - for arg in op.args: - self._push(arg) - - # compute and store value - self.ilasm.opcode(cli_opcode) - self._store(op.result) def _push(self, v): if isinstance(v, flowmodel.Variable): if v.name in self.argset: - self.ilasm.opcode('ldarg.s', repr(v.name)) + self.ilasm.opcode('ldarg', repr(v.name)) else: - self.ilasm.opcode('ldloc.s', repr(v.name)) + self.ilasm.opcode('ldloc', repr(v.name)) elif isinstance(v, flowmodel.Constant): iltype, ilvalue = cts.llconst_to_ilasm(v) @@ -182,6 +186,6 @@ def _store(self, v): if isinstance(v, flowmodel.Variable): - self.ilasm.opcode('stloc.s', repr(v.name)) + self.ilasm.opcode('stloc', repr(v.name)) else: assert False Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Thu Mar 23 23:07:56 2006 @@ -67,13 +67,13 @@ self.code.writeline() def branch(self, lbl): - self.code.writeline('br.s ' + lbl) + self.code.writeline('br ' + lbl) def branch_if(self, cond, lbl): if cond: - opcode = 'brtrue.s ' + opcode = 'brtrue ' else: - opcode = 'brfalse.s ' + opcode = 'brfalse ' self.code.writeline(opcode + lbl) Added: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/opcodes.py Thu Mar 23 23:07:56 2006 @@ -0,0 +1,172 @@ +DoNothing = object() +PushArgs = object() + +# come useful instruction patterns +Not = ['ldc.i4.0', 'ceq'] + +def _not(op): + return [PushArgs, op]+Not + + +opcodes = { + 'same_as': DoNothing, # TODO: does same_as really do nothing else than renaming? + 'direct_call': None, # for now it's a special case + 'indirect_call': None, + + # __________ numeric operations __________ + + 'bool_not': Not, + + 'char_lt': 'clt', + 'char_le': None, + 'char_eq': 'ceq', + 'char_ne': None, + 'char_gt': None, + 'char_ge': None, + + 'unichar_eq': None, + 'unichar_ne': None, + + 'int_is_true': DoNothing, + 'int_neg': 'neg', + 'int_neg_ovf': ['ldc.i4.0', PushArgs, 'sub.ovf'], + 'int_abs': None, # TODO + 'int_abs_ovf': None, # TODO + 'int_invert': 'not', + + 'int_add': 'add', + 'int_sub': 'sub', + 'int_mul': 'mul', + 'int_div': 'div', + 'int_truediv': None, # TODO + 'int_floordiv': 'div', + 'int_mod': 'rem', + 'int_lt': 'clt', + 'int_le': _not('cgt'), + 'int_eq': 'ceq', + 'int_ne': _not('ceq'), + 'int_gt': 'cgt', + 'int_ge': _not('clt'), + 'int_and': 'and', + 'int_or': 'or', + 'int_lshift': 'shl', + 'int_rshift': 'shr', + 'int_xor': 'xor', + 'int_add_ovf': None, + 'int_sub_ovf': None, + 'int_mul_ovf': None, + 'int_div_ovf': None, + 'int_truediv_ovf': None, + 'int_floordiv_ovf': None, + 'int_mod_ovf': None, + 'int_lt_ovf': None, + 'int_le_ovf': None, + 'int_eq_ovf': None, + 'int_ne_ovf': None, + 'int_gt_ovf': None, + 'int_ge_ovf': None, + 'int_and_ovf': None, + 'int_or_ovf': None, + 'int_lshift_ovf': None, + 'int_rshift_ovf': None, + 'int_xor_ovf': None, + 'int_floordiv_ovf_zer': None, + 'int_mod_ovf_zer': None, + + 'uint_is_true': None, + 'uint_neg': None, + 'uint_abs': None, + 'uint_invert': None, + + 'uint_add': None, + 'uint_sub': None, + 'uint_mul': None, + 'uint_div': None, + 'uint_truediv': None, + 'uint_floordiv': None, + 'uint_mod': None, + 'uint_lt': None, + 'uint_le': None, + 'uint_eq': None, + 'uint_ne': None, + 'uint_gt': None, + 'uint_ge': None, + 'uint_and': None, + 'uint_or': None, + 'uint_lshift': None, + 'uint_rshift': None, + 'uint_xor': None, + + 'float_is_true': None, + 'float_neg': None, + 'float_abs': None, + + 'float_add': None, + 'float_sub': None, + 'float_mul': None, + 'float_div': None, + 'float_truediv': None, + 'float_floordiv': None, + 'float_mod': None, + 'float_lt': None, + 'float_le': None, + 'float_eq': None, + 'float_ne': None, + 'float_gt': None, + 'float_ge': None, + 'float_floor': None, + 'float_fmod': None, + + 'llong_is_true': None, + 'llong_neg': None, + 'llong_abs': None, + 'llong_invert': None, + + 'llong_add': None, + 'llong_sub': None, + 'llong_mul': None, + 'llong_div': None, + 'llong_truediv': None, + 'llong_floordiv': None, + 'llong_mod': None, + 'llong_lt': None, + 'llong_le': None, + 'llong_eq': None, + 'llong_ne': None, + 'llong_gt': None, + 'llong_ge': None, + + 'ullong_is_true': None, + 'ullong_neg': None, + 'ullong_abs': None, + 'ullong_invert': None, + + 'ullong_add': None, + 'ullong_sub': None, + 'ullong_mul': None, + 'ullong_div': None, + 'ullong_truediv': None, + 'ullong_floordiv': None, + 'ullong_mod': None, + 'ullong_lt': None, + 'ullong_le': None, + 'ullong_eq': None, + 'ullong_ne': None, + 'ullong_gt': None, + 'ullong_ge': None, + + 'cast_bool_to_int': None, + 'cast_bool_to_uint': None, + 'cast_bool_to_float': None, + 'cast_char_to_int': None, + 'cast_unichar_to_int': None, + 'cast_int_to_char': None, + 'cast_int_to_unichar': None, + 'cast_int_to_uint': None, + 'cast_int_to_float': None, + 'cast_int_to_longlong': None, + 'cast_uint_to_int': None, + 'cast_float_to_int': None, + 'cast_float_to_uint': None, + 'truncate_longlong_to_int': None +} Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Thu Mar 23 23:07:56 2006 @@ -1,19 +1,35 @@ #!/bin/env python import py +from pypy.translator.test import snippet as s from pypy.translator.cli import conftest from pypy.translator.cli.test.runtest import compile_function py.test.Config.parse(py.std.sys.argv[1:]) #conftest.option.view = True -conftest.option.source = True +#conftest.option.source = True conftest.option.wd = True -conftest.option.nostop = True -conftest.option.stdout = True +#conftest.option.nostop = True +#conftest.option.stdout = True + +def check(f, g, *args): + x = f(*args) + y = g(*args) + if x != y: + print x, '!=', y + else: + print 'OK' + def bar(x, y): - return x/y + return x>>3 + y<<2 + f = compile_function(bar, [int, int]) + +check(f, bar, 3, 3) +check(f, bar, 4, 5) + +#compile_function(s.is_perfect_number, [int]) Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Thu Mar 23 23:07:56 2006 @@ -8,6 +8,11 @@ from pypy.translator.cli.gencli import GenCli from pypy.translator.cli.function import Node from pypy.translator.cli.cts import graph_to_signature +from pypy.translator.cli.cts import llvar_to_cts + +def check(func, annotation, args): + mono = compile_function(func, annotation) + assert func(*args) == mono(*args) class TestEntryPoint(Node): """ @@ -24,15 +29,19 @@ def render(self, ilasm): ilasm.begin_function('main', [('string[]', 'argv')], 'void', True) - # TODO: add support for non-int32 types + # TODO: only int32 and bool are tested for i, arg in enumerate(self.graph.getargs()): ilasm.opcode('ldarg.0') ilasm.opcode('ldc.i4.%d' % i) ilasm.opcode('ldelem.ref') - ilasm.call('int32 class [mscorlib]System.Convert::ToInt32(string)') + arg_type, arg_var = llvar_to_cts(arg) + ilasm.call('int32 class [mscorlib]System.Convert::To%s(string)' % arg_type.capitalize()) ilasm.call(graph_to_signature(self.graph)) - ilasm.call('void class [mscorlib]System.Console::WriteLine(int32)') + + # print the result using the appropriate WriteLine overload + ret_type, ret_var = llvar_to_cts(self.graph.getreturnvar()) + ilasm.call('void class [mscorlib]System.Console::WriteLine(%s)' % ret_type) ilasm.opcode('ret') ilasm.end_function() @@ -89,7 +98,6 @@ return tmpfile.replace('.il', '.exe') def __call__(self, *args): - # NB: only integers arguments are supported currently if self._exe is None: py.test.skip("Compilation disabled") @@ -99,4 +107,11 @@ stdout, stderr = mono.communicate() retval = mono.wait() assert retval == 0, stderr - return int(stdout) + + ret_type, ret_var = llvar_to_cts(self.graph.getreturnvar()) + if ret_type == 'int32': + return int(stdout) + elif ret_type == 'bool': + return stdout.strip().lower() == 'true' + else: + assert False, 'Return type %s is not supported' % ret_type Modified: pypy/dist/pypy/translator/cli/test/test_flow.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_flow.py (original) +++ pypy/dist/pypy/translator/cli/test/test_flow.py Thu Mar 23 23:07:56 2006 @@ -1,5 +1,5 @@ from pypy.translator.test import snippet as s -from pypy.translator.cli.test.runtest import compile_function +from pypy.translator.cli.test.runtest import check def fibo(n): """Compute the (n+1)th Fibonacci's number""" @@ -15,13 +15,13 @@ [s.if_then_else, [int, int, int], (0, 42, 43), (1, 42, 43)], [s.simple_func, [int], (42,)], [s.while_func, [int], (0,), (13,)], - [fibo, [int], (0,), (1,), (10,)] + [fibo, [int], (0,), (1,), (10,)], + [s.my_bool, [int], (0,), (42,)], + [s.my_gcd, [int, int], (30, 18)], + [s.is_perfect_number, [int], (28,), (27,)], ] -def check(func, annotation, args): - mono = compile_function(func, annotation) - assert func(*args) == mono(*args) def test_snippets(): for item in snippets: Added: pypy/dist/pypy/translator/cli/test/test_op.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/test/test_op.py Thu Mar 23 23:07:56 2006 @@ -0,0 +1,25 @@ +from pypy.translator.cli.test.runtest import check + +def test_op(): + for name, func in globals().iteritems(): + if name.startswith('op_'): + yield check, func, [int, int], (3, 4) + + +def op_neg(x, y): + return -x + +def op_less_equal(x, y): + return x<=y + +def op_and_not(x, y): + return x and (not y) + +def op_shift(x, y): + return x<<3 + y>>4 + +def op_bit_and_or_not_xor(x, y): + return (x&y) | ~(x^y) + +def op_operations(x, y): + return (x*y) / (x-y) +(-x) From pedronis at codespeak.net Thu Mar 23 23:46:01 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Mar 2006 23:46:01 +0100 (CET) Subject: [pypy-svn] r24919 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060323224601.C8D6D10151@code0.codespeak.net> Author: pedronis Date: Thu Mar 23 23:45:55 2006 New Revision: 24919 Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py Log: XXX reminder of leak problem with current code! Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Thu Mar 23 23:45:55 2006 @@ -189,6 +189,7 @@ assert len(block.inputargs) == 1 # regular return block if self.cpython_exc: + # XXX leaks! assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr yield 'if (RPyExceptionOccurred()) {' yield '\tRPyConvertExceptionToCPython(rpython_exc_value);' From antocuni at codespeak.net Thu Mar 23 23:47:42 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 23 Mar 2006 23:47:42 +0100 (CET) Subject: [pypy-svn] r24920 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060323224742.557F810155@code0.codespeak.net> Author: antocuni Date: Thu Mar 23 23:47:17 2006 New Revision: 24920 Added: pypy/dist/pypy/translator/cli/test/test_snippet.py - copied unchanged from r24918, pypy/dist/pypy/translator/cli/test/test_flow.py Removed: pypy/dist/pypy/translator/cli/test/test_flow.py Modified: pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/cli/test/compile.py pypy/dist/pypy/translator/cli/test/runtest.py Log: Added Windows support to testing procedure Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Thu Mar 23 23:47:17 2006 @@ -37,6 +37,7 @@ def __init__(self, outfile, name): self.out = outfile self.code = CodeGenerator(self.out) + self.code.writeline('.assembly extern mscorlib {}') self.code.writeline('.assembly %s {}' % name) def close(self): @@ -57,7 +58,7 @@ def locals(self, vars): varlist = ', '.join(['%s %s' % var for var in vars]) - self.code.write('.locals (') + self.code.write('.locals init (') self.code.write(varlist) self.code.writeline(')') Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Thu Mar 23 23:47:17 2006 @@ -23,7 +23,10 @@ def bar(x, y): - return x>>3 + y<<2 + if x>y: + return x + else: + return y Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Thu Mar 23 23:47:17 2006 @@ -1,5 +1,6 @@ import os import subprocess +import platform import py from pypy.tool.udir import udir @@ -46,8 +47,6 @@ ilasm.end_function() - - class compile_function: def __init__(self, func, annotation=[], graph=None): self._func = func @@ -83,10 +82,17 @@ def __check_helper(self, helper): try: - py.path.local.sysfind(helper) # TODO: support windows + py.path.local.sysfind(helper) except py.error.ENOENT: py.test.skip("%s is not on your path." % helper) + def __get_runtime(self): + if platform.system() == 'Windows': + return [] + else: + self.__check_helper('mono') + return ['mono'] + def _build_exe(self): tmpfile = self._gen.generate_source() if conftest.option.source: @@ -101,8 +107,8 @@ if self._exe is None: py.test.skip("Compilation disabled") - self.__check_helper("mono") - arglist = ["mono", self._exe] + map(str, args) + runtime = self.__get_runtime() + arglist = runtime + [self._exe] + map(str, args) mono = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = mono.communicate() retval = mono.wait() From tismer at codespeak.net Fri Mar 24 01:14:52 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 01:14:52 +0100 (CET) Subject: [pypy-svn] r24924 - pypy/dist/pypy/translator/c/test Message-ID: <20060324001452.7AA8B10141@code0.codespeak.net> Author: tismer Date: Fri Mar 24 01:14:43 2006 New Revision: 24924 Modified: pypy/dist/pypy/translator/c/test/test_genc.py Log: waah, this crash was hard to make reproducible - does it after 30 runs, or never. Modified: pypy/dist/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_genc.py (original) +++ pypy/dist/pypy/translator/c/test/test_genc.py Fri Mar 24 01:14:43 2006 @@ -386,3 +386,14 @@ res = f1(1) assert res == 202 # state.current == 2 + +# this test crashes after 30 runs on my XP machine +def test_refcount_pyobj(): + def prob_with_pyobj(a=int, b=int): + return 2, 3, long(42) + + f = compile(prob_with_pyobj, [int, int]) + ret = f(2, 3) + for i in xrange(1000): + print i + f(2, 3) From tismer at codespeak.net Fri Mar 24 04:38:48 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 04:38:48 +0100 (CET) Subject: [pypy-svn] r24926 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20060324033848.C793010145@code0.codespeak.net> Author: tismer Date: Fri Mar 24 04:38:34 2006 New Revision: 24926 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py Log: support for instance export temporarily here Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Fri Mar 24 04:38:34 2006 @@ -17,6 +17,8 @@ RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, \ Array, Char, Void, attachRuntimeTypeInfo, \ FuncType, Bool, Signed, functionptr, FuncType +from pypy.rpython.robject import PyObjRepr, pyobj_repr +from pypy.rpython import extregistry # # There is one "vtable" per user class, with the following structure: @@ -576,6 +578,44 @@ v = rpair.rtype_eq(hop) return hop.genop("bool_not", [v], resulttype=Bool) +# +# _________________________ Conversions for CPython _________________________ + + +def call_destructor(thing): + ll_call_destructor(thing) + +def ll_call_destructor(thang): + return 42 # will be mapped + +def rtype_destruct_object(hop): + v_any, = hop.inputargs(*hop.args_r) + hop.genop('gc_unprotect', [v_any]) + +extregistry.register_value(ll_call_destructor, + compute_result_annotation=lambda *args:None, + specialize_call=rtype_destruct_object) + +class __extend__(pairtype(PyObjRepr, InstanceRepr)): + def convert_from_to((r_from, r_to), v, llops): + v_adr = llops.gencapicall('PyCObject_AsVoidPtr', [v], + resulttype=r_to) + llops.genop('gc_protect', [v_adr]) + return v_adr + +class __extend__(pairtype(InstanceRepr, PyObjRepr)): + def convert_from_to((r_from, r_to), v, llops): + f = call_destructor + llops.genop('gc_protect', [v]) + ARGTYPE = r_from.lowleveltype + FUNCTYPE = FuncType([ARGTYPE], Void) + fp_dtor = llops.rtyper.annotate_helper_fn(f, [ARGTYPE]) + c_dtor = inputconst(Ptr(FUNCTYPE), fp_dtor) + v_result = llops.gencapicall('PyCObject_FromVoidPtr', [v, c_dtor], + resulttype=pyobj_repr) + return v_result + +# ____________________________________________________________ def ll_both_none(ins1, ins2): return not ins1 and not ins2 From tismer at codespeak.net Fri Mar 24 04:39:47 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 04:39:47 +0100 (CET) Subject: [pypy-svn] r24927 - pypy/dist/pypy/rpython Message-ID: <20060324033947.53E0F10145@code0.codespeak.net> Author: tismer Date: Fri Mar 24 04:39:44 2006 New Revision: 24927 Modified: pypy/dist/pypy/rpython/normalizecalls.py Log: record generated instantiators in the graph Modified: pypy/dist/pypy/rpython/normalizecalls.py ============================================================================== --- pypy/dist/pypy/rpython/normalizecalls.py (original) +++ pypy/dist/pypy/rpython/normalizecalls.py Fri Mar 24 04:39:44 2006 @@ -270,6 +270,7 @@ generalizedresult = annmodel.SomeInstance(classdef=None) annotator.setbinding(graph.getreturnvar(), generalizedresult) classdef.my_instantiate_graph = graph + annotator.translator.graphs.append(graph) # ____________________________________________________________ From tismer at codespeak.net Fri Mar 24 04:47:12 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 04:47:12 +0100 (CET) Subject: [pypy-svn] r24928 - pypy/dist/pypy/translator/c/test Message-ID: <20060324034712.D50BE1014D@code0.codespeak.net> Author: tismer Date: Fri Mar 24 04:47:00 2006 New Revision: 24928 Modified: pypy/dist/pypy/translator/c/test/test_genc.py Log: modified the test to still complain about refcounts but without crashing the machine Modified: pypy/dist/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_genc.py (original) +++ pypy/dist/pypy/translator/c/test/test_genc.py Fri Mar 24 04:47:00 2006 @@ -389,11 +389,13 @@ # this test crashes after 30 runs on my XP machine def test_refcount_pyobj(): - def prob_with_pyobj(a=int, b=int): - return 2, 3, long(42) + def prob_with_pyobj(a, b): + return 2, 3, b - f = compile(prob_with_pyobj, [int, int]) - ret = f(2, 3) - for i in xrange(1000): - print i - f(2, 3) + f = compile(prob_with_pyobj, [int, object]) + from sys import getrefcount as g + obj = None + before = g(obj) + f(2, obj) + after = g(obj) + assert before == after \ No newline at end of file From tismer at codespeak.net Fri Mar 24 04:49:38 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 04:49:38 +0100 (CET) Subject: [pypy-svn] r24929 - pypy/dist/pypy/translator/c/test Message-ID: <20060324034938.36B961014D@code0.codespeak.net> Author: tismer Date: Fri Mar 24 04:49:31 2006 New Revision: 24929 Modified: pypy/dist/pypy/translator/c/test/test_genc.py Log: comment Modified: pypy/dist/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_genc.py (original) +++ pypy/dist/pypy/translator/c/test/test_genc.py Fri Mar 24 04:49:31 2006 @@ -387,7 +387,7 @@ assert res == 202 # state.current == 2 -# this test crashes after 30 runs on my XP machine +# this test shows if we have a problem with refcounting PyObject def test_refcount_pyobj(): def prob_with_pyobj(a, b): return 2, 3, b From tismer at codespeak.net Fri Mar 24 05:03:18 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 05:03:18 +0100 (CET) Subject: [pypy-svn] r24930 - in pypy/dist/pypy/translator/c: . winproj/extension Message-ID: <20060324040318.B6AAF10145@code0.codespeak.net> Author: tismer Date: Fri Mar 24 05:03:14 2006 New Revision: 24930 Modified: pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Log: supporting class export Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Fri Mar 24 05:03:14 2006 @@ -31,8 +31,9 @@ if libraries is None: libraries = [] self.libraries = libraries + self.exports = {} - def build_database(self): + def build_database(self, exports=[]): translator = self.translator db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicy=self.gcpolicy, thread_enabled=self.thread_enabled) @@ -53,7 +54,16 @@ # some needed things. Find out why. pf = self.getentrypointptr() pfname = db.get(pf) - # XXX + self.exports[self.entrypoint.func_name] = pf + for obj in exports: + po = self.getentrypointptr(obj) + poname = objname = db.get(po) + if hasattr(obj, '__name__'): + objname = obj.__name__ + if objname in self.exports: + raise NameError, 'duplicate name in export: %s is %s and %s' % ( + objname, db.get(self.exports[objname]), poname) + self.exports[objname] = po db.complete() return db @@ -80,7 +90,7 @@ self.symboltable = SymbolTable() cfile, extra = gen_source(db, modulename, targetdir, defines = defines, - exports = {self.entrypoint.func_name: pf}, + exports = self.exports, symboltable = self.symboltable) else: if CBuilder.have___thread: @@ -105,8 +115,10 @@ standalone = False c_ext_module = None - def getentrypointptr(self): - return lltype.pyobjectptr(self.entrypoint) + def getentrypointptr(self, obj=None): + if obj is None: + obj = self.entrypoint + return lltype.pyobjectptr(obj) def compile(self): assert self.c_source_filename Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Fri Mar 24 05:03:14 2006 @@ -208,10 +208,7 @@ - - + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-964\testing_1\testing_1.c"> From tismer at codespeak.net Fri Mar 24 05:40:22 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 24 Mar 2006 05:40:22 +0100 (CET) Subject: [pypy-svn] r24932 - pypy/dist/pypy/translator/c/test Message-ID: <20060324044022.1F11A10145@code0.codespeak.net> Author: tismer Date: Fri Mar 24 05:40:16 2006 New Revision: 24932 Added: pypy/dist/pypy/translator/c/test/test_wrapping.py - copied unchanged from r24931, user/tismer/test_wrapping.py Log: copied my almost working test of building extension modules. some work is left, need to change the generated python code to do the indirection tricks. From gromit at codespeak.net Fri Mar 24 09:29:01 2006 From: gromit at codespeak.net (gromit at codespeak.net) Date: Fri, 24 Mar 2006 09:29:01 +0100 (CET) Subject: [pypy-svn] r24938 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060324082901.1F3331014D@code0.codespeak.net> Author: gromit Date: Fri Mar 24 09:28:48 2006 New Revision: 24938 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: ADD: My one Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Fri Mar 24 09:28:48 2006 @@ -22,6 +22,7 @@ Niklaus Haldimann 2/4 - 5/4 Ermina Aurelien Campeas 3/4 - 7/4 Ermina Alexandre Fayolle 3/4 - 7/4 Ermina +Gerald Klix 6/4? - 9/4 Ermina ==================== ============== ===================== People on the following list were present at previous sprints: From nik at codespeak.net Fri Mar 24 10:32:43 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 24 Mar 2006 10:32:43 +0100 (CET) Subject: [pypy-svn] r24940 - in pypy/dist/pypy: jit rpython rpython/lltypesystem rpython/ootypesystem rpython/test translator/squeak/test Message-ID: <20060324093243.D59A010145@code0.codespeak.net> Author: nik Date: Fri Mar 24 10:32:40 2006 New Revision: 24940 Added: pypy/dist/pypy/rpython/lltypesystem/rtuple.py - copied, changed from r24667, pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/ootypesystem/rtuple.py Modified: pypy/dist/pypy/jit/hinttimeshift.py pypy/dist/pypy/rpython/callparse.py pypy/dist/pypy/rpython/lltypesystem/rpbc.py pypy/dist/pypy/rpython/rstr.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/rtyper.py pypy/dist/pypy/rpython/test/test_rtuple.py pypy/dist/pypy/rpython/typesystem.py pypy/dist/pypy/translator/squeak/test/runtest.py Log: split rtuple into a version for the lltypesystem and the ootypesystem. make some tuple tests pass on ootypes. the ootype version is for now conceptually analoguous to the lltype one. this is a slightly invasive change, but as far as i can tell it doesn't break any tests or translation. Modified: pypy/dist/pypy/jit/hinttimeshift.py ============================================================================== --- pypy/dist/pypy/jit/hinttimeshift.py (original) +++ pypy/dist/pypy/jit/hinttimeshift.py Fri Mar 24 10:32:40 2006 @@ -4,7 +4,8 @@ from pypy.annotation import listdef, dictdef from pypy.jit.rtimeshift import VARLIST, RedBox, VarRedBox, ConstRedBox, JITState from pypy.jit.rtimeshift import make_types_const -from pypy.rpython import rmodel, rtuple, rlist, rdict, rgenop, annlowlevel +from pypy.rpython import rmodel, rlist, rdict, rgenop, annlowlevel +from pypy.rpython.lltypesystem import rtuple from pypy.jit import rtimeshift from pypy.jit.hintrtyper import HintRTyper, originalconcretetype from pypy.jit.hintrtyper import GreenRepr, RedRepr, HintLowLevelOpList Modified: pypy/dist/pypy/rpython/callparse.py ============================================================================== --- pypy/dist/pypy/rpython/callparse.py (original) +++ pypy/dist/pypy/rpython/callparse.py Fri Mar 24 10:32:40 2006 @@ -1,6 +1,6 @@ from pypy.interpreter.argument import Arguments, ArgErr from pypy.annotation import model as annmodel -from pypy.rpython import rtuple +from pypy.rpython.lltypesystem import rtuple # XXX not independent of type system! from pypy.rpython.error import TyperError from pypy.rpython.lltypesystem import lltype Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rpbc.py Fri Mar 24 10:32:40 2006 @@ -7,8 +7,6 @@ typeOf, Void, ForwardReference, Struct, Bool, \ Ptr, malloc, nullptr from pypy.rpython.rmodel import Repr, TyperError, inputconst, inputdesc -from pypy.rpython import robject -from pypy.rpython import rtuple from pypy.rpython.rpbc import samesig,\ commonbase, allattributenames, adjust_shape, \ AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr, \ Added: pypy/dist/pypy/rpython/ootypesystem/rtuple.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/ootypesystem/rtuple.py Fri Mar 24 10:32:40 2006 @@ -0,0 +1,62 @@ +from pypy.annotation.pairtype import pairtype +from pypy.objspace.flow.model import Constant +from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst +from pypy.rpython.rmodel import externalvsinternal +from pypy.rpython.error import TyperError +from pypy.rpython.rtuple import AbstractTupleRepr +from pypy.rpython.ootypesystem import ootype + + +class TupleRepr(AbstractTupleRepr): + + def __init__(self, rtyper, items_r): + AbstractTupleRepr.__init__(self, rtyper, items_r) + self.lowleveltype = tuple_type(self.fieldnames, self.lltypes) + + def instantiate(self): + return ootype.new(self.lowleveltype) + + def getitem(self, llops, v_tuple, index): # ! returns internal repr lowleveltype + name = self.fieldnames[index] + llresult = self.lltypes[index] + cname = inputconst(ootype.Void, name) + return llops.genop("oogetfield", [v_tuple, cname], resulttype=llresult) + + +_tuple_types = {} + +def tuple_type(fieldnames, fieldtypes): + key = tuple(fieldtypes) + if _tuple_types.has_key(key): + return _tuple_types[key] + else: + fields = dict(zip(fieldnames, fieldtypes)) + INST = ootype.Instance("Tuple%s" % len(fieldnames), ootype.ROOT, fields) + _tuple_types[key] = INST + return INST +# ____________________________________________________________ +# +# Irregular operations. + +def newtuple(llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs + if len(r_tuple.items_r) == 0: + return inputconst(r_tuple, ()) # always the same empty tuple + c1 = inputconst(ootype.Void, r_tuple.lowleveltype) + v_result = llops.genop("new", [c1], resulttype=r_tuple.lowleveltype) + for i in range(len(r_tuple.items_r)): + cname = inputconst(ootype.Void, r_tuple.fieldnames[i]) + llops.genop("oosetfield", [v_result, cname, items_v[i]]) + return v_result + +def newtuple_cached(hop, items_v): + r_tuple = hop.r_result + if hop.s_result.is_constant(): + return inputconst(r_tuple, hop.s_result.const) + else: + return newtuple(hop.llops, r_tuple, items_v) + +def rtype_newtuple(hop): + r_tuple = hop.r_result + vlist = hop.inputargs(*r_tuple.items_r) + return newtuple_cached(hop, vlist) + Modified: pypy/dist/pypy/rpython/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/rstr.py (original) +++ pypy/dist/pypy/rpython/rstr.py Fri Mar 24 10:32:40 2006 @@ -6,7 +6,7 @@ from pypy.rpython.rmodel import StringRepr, CharRepr, inputconst, UniCharRepr from pypy.rpython.rarithmetic import _hash_string from pypy.rpython.robject import PyObjRepr, pyobj_repr -from pypy.rpython.rtuple import TupleRepr +from pypy.rpython.lltypesystem.rtuple import TupleRepr # XXX type system! from pypy.rpython import rint from pypy.rpython.rslice import SliceRepr from pypy.rpython.rslice import startstop_slice_repr, startonly_slice_repr Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Fri Mar 24 10:32:40 2006 @@ -11,82 +11,16 @@ Ptr, GcStruct, Void, Signed, malloc, typeOf, nullptr from pypy.rpython.rarithmetic import intmask -# ____________________________________________________________ -# -# Concrete implementation of RPython tuples: -# -# struct tuple { -# type0 item0; -# type1 item1; -# type2 item2; -# ... -# } - class __extend__(annmodel.SomeTuple): def rtyper_makerepr(self, rtyper): - return TupleRepr(rtyper, [rtyper.getrepr(s_item) for s_item in self.items]) + repr_class = rtyper.type_system.rtuple.TupleRepr + return repr_class(rtyper, [rtyper.getrepr(s_item) for s_item in self.items]) def rtyper_makekey_ex(self, rtyper): keys = [rtyper.makekey(s_item) for s_item in self.items] return tuple([self.__class__]+keys) -_gen_eq_function_cache = {} -_gen_hash_function_cache = {} - -def gen_eq_function(items_r): - eq_funcs = [r_item.get_ll_eq_function() or operator.eq for r_item in items_r] - key = tuple(eq_funcs) - try: - return _gen_eq_function_cache[key] - except KeyError: - miniglobals = {} - source = """ -def ll_eq(t1, t2): - %s - return True -""" - body = [] - for i, eq_func in enumerate(eq_funcs): - miniglobals['eq%d' % i] = eq_func - body.append("if not eq%d(t1.item%d, t2.item%d): return False" % (i, i, i)) - body = ('\n'+' '*4).join(body) - source = source % body - exec source in miniglobals - ll_eq = miniglobals['ll_eq'] - _gen_eq_function_cache[key] = ll_eq - return ll_eq - -def gen_hash_function(items_r): - # based on CPython - hash_funcs = [r_item.get_ll_hash_function() for r_item in items_r] - key = tuple(hash_funcs) - try: - return _gen_hash_function_cache[key] - except KeyError: - miniglobals = {} - source = """ -def ll_hash(t): - retval = 0x345678 - %s - return retval -""" - body = [] - mult = 1000003 - for i, hash_func in enumerate(hash_funcs): - miniglobals['hash%d' % i] = hash_func - body.append("retval = (retval ^ hash%d(t.item%d)) * %d" % - (i, i, mult)) - mult = intmask(mult + 82520 + 2*len(items_r)) - body = ('\n'+' '*4).join(body) - source = source % body - exec source in miniglobals - ll_hash = miniglobals['ll_hash'] - _gen_hash_function_cache[key] = ll_hash - return ll_hash - - - -class TupleRepr(Repr): +class AbstractTupleRepr(Repr): def __init__(self, rtyper, items_r): self.items_r = [] @@ -98,93 +32,25 @@ items_r = self.items_r self.fieldnames = ['item%d' % i for i in range(len(items_r))] self.lltypes = [r.lowleveltype for r in items_r] - fields = zip(self.fieldnames, self.lltypes) - self.lowleveltype = Ptr(GcStruct('tuple%d' % len(items_r), *fields)) self.tuple_cache = {} - def compact_repr(self): - return "TupleR %s" % ' '.join([llt._short_name() for llt in self.lltypes]) - def convert_const(self, value): assert isinstance(value, tuple) and len(value) == len(self.items_r) key = tuple([Constant(item) for item in value]) try: return self.tuple_cache[key] except KeyError: - p = malloc(self.lowleveltype.TO) + p = self.instantiate() self.tuple_cache[key] = p for obj, r, name in zip(value, self.items_r, self.fieldnames): setattr(p, name, r.convert_const(obj)) return p - #def get_eqfunc(self): - # return inputconst(Void, self.item_repr.get_ll_eq_function()) - - def get_ll_eq_function(self): - return gen_eq_function(self.items_r) - - def get_ll_hash_function(self): - return gen_hash_function(self.items_r) - - def can_ll_be_null(self, s_value): - return False - def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) - def rtype_bltn_list(self, hop): - from pypy.rpython import rlist - nitems = len(self.items_r) - vtup = hop.inputarg(self, 0) - LIST = hop.r_result.lowleveltype.TO - cno = inputconst(Signed, nitems) - vlist = hop.gendirectcall(LIST.ll_newlist, cno) - v_func = hop.inputconst(Void, rlist.dum_nocheck) - for index in range(nitems): - name = self.fieldnames[index] - ritem = self.items_r[index] - cname = hop.inputconst(Void, name) - vitem = hop.genop('getfield', [vtup, cname], resulttype = ritem) - vitem = hop.llops.convertvar(vitem, ritem, hop.r_result.item_repr) - cindex = inputconst(Signed, index) - hop.gendirectcall(rlist.ll_setitem_nonneg, v_func, vlist, cindex, vitem) - return vlist - - def make_iterator_repr(self): - if len(self.items_r) == 1: - return Length1TupleIteratorRepr(self) - raise TyperError("can only iterate over tuples of length 1 for now") - - def getitem(self, llops, v_tuple, index): # ! returns internal repr lowleveltype - name = self.fieldnames[index] - llresult = self.lltypes[index] - cname = inputconst(Void, name) - return llops.genop('getfield', [v_tuple, cname], resulttype = llresult) - - -class __extend__(pairtype(TupleRepr, Repr)): - def rtype_contains((r_tup, r_item), hop): - s_tup = hop.args_s[0] - if not s_tup.is_constant(): - raise TyperError("contains() on non-const tuple") - t = s_tup.const - typ = type(t[0]) - for x in t[1:]: - if type(x) is not typ: - raise TyperError("contains() on mixed-type tuple " - "constant %r" % (t,)) - d = {} - for x in t: - d[x] = None - hop2 = hop.copy() - _, _ = hop2.r_s_popfirstarg() - v_dict = Constant(d) - s_dict = hop.rtyper.annotator.bookkeeper.immutablevalue(d) - hop2.v_s_insertfirstarg(v_dict, s_dict) - return hop2.dispatch() - -class __extend__(pairtype(TupleRepr, IntegerRepr)): +class __extend__(pairtype(AbstractTupleRepr, IntegerRepr)): def rtype_getitem((r_tup, r_int), hop): v_tuple, v_index = hop.inputargs(r_tup, Signed) @@ -194,123 +60,3 @@ v = r_tup.getitem(hop.llops, v_tuple, index) return hop.llops.convertvar(v, r_tup.items_r[index], r_tup.external_items_r[index]) -class __extend__(pairtype(TupleRepr, TupleRepr)): - - def rtype_add((r_tup1, r_tup2), hop): - v_tuple1, v_tuple2 = hop.inputargs(r_tup1, r_tup2) - vlist = [] - for i in range(len(r_tup1.items_r)): - vlist.append(r_tup1.getitem(hop.llops, v_tuple1, i)) - for i in range(len(r_tup2.items_r)): - vlist.append(r_tup2.getitem(hop.llops, v_tuple2, i)) - return newtuple_cached(hop, vlist) - rtype_inplace_add = rtype_add - - def convert_from_to((r_from, r_to), v, llops): - if len(r_from.items_r) == len(r_to.items_r): - if r_from.lowleveltype == r_to.lowleveltype: - return v - n = len(r_from.items_r) - items_v = [] - for i in range(n): - item_v = r_from.getitem(llops, v, i) - item_v = llops.convertvar(item_v, - r_from.items_r[i], - r_to.items_r[i]) - items_v.append(item_v) - return newtuple(llops, r_to, items_v) - return NotImplemented - -# ____________________________________________________________ -# -# Irregular operations. - -def newtuple(llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs - if len(r_tuple.items_r) == 0: - return inputconst(r_tuple, ()) # always the same empty tuple - c1 = inputconst(Void, r_tuple.lowleveltype.TO) - v_result = llops.genop('malloc', [c1], resulttype = r_tuple.lowleveltype) - for i in range(len(r_tuple.items_r)): - cname = inputconst(Void, r_tuple.fieldnames[i]) - llops.genop('setfield', [v_result, cname, items_v[i]]) - return v_result - -def newtuple_cached(hop, items_v): - r_tuple = hop.r_result - if hop.s_result.is_constant(): - return inputconst(r_tuple, hop.s_result.const) - else: - return newtuple(hop.llops, r_tuple, items_v) - -def rtype_newtuple(hop): - r_tuple = hop.r_result - vlist = hop.inputargs(*r_tuple.items_r) - return newtuple_cached(hop, vlist) - -# -# _________________________ Conversions _________________________ - -class __extend__(pairtype(PyObjRepr, TupleRepr)): - def convert_from_to((r_from, r_to), v, llops): - vlist = [] - for i in range(len(r_to.items_r)): - ci = inputconst(Signed, i) - v_item = llops.gencapicall('PyTuple_GetItem_WithIncref', [v, ci], - resulttype = pyobj_repr) - v_converted = llops.convertvar(v_item, pyobj_repr, - r_to.items_r[i]) - vlist.append(v_converted) - return newtuple(llops, r_to, vlist) - -class __extend__(pairtype(TupleRepr, PyObjRepr)): - def convert_from_to((r_from, r_to), v, llops): - ci = inputconst(Signed, len(r_from.items_r)) - v_result = llops.gencapicall('PyTuple_New', [ci], - resulttype = pyobj_repr) - for i in range(len(r_from.items_r)): - cname = inputconst(Void, r_from.fieldnames[i]) - v_item = llops.genop('getfield', [v, cname], - resulttype = r_from.items_r[i].lowleveltype) - v_converted = llops.convertvar(v_item, r_from.items_r[i], - pyobj_repr) - ci = inputconst(Signed, i) - llops.gencapicall('PyTuple_SetItem_WithIncref', [v_result, ci, - v_converted]) - return v_result - -# ____________________________________________________________ -# -# Iteration. - -class Length1TupleIteratorRepr(IteratorRepr): - - def __init__(self, r_tuple): - self.r_tuple = r_tuple - self.lowleveltype = Ptr(GcStruct('tuple1iter', - ('tuple', r_tuple.lowleveltype))) - - def newiter(self, hop): - v_tuple, = hop.inputargs(self.r_tuple) - citerptr = hop.inputconst(Void, self.lowleveltype) - return hop.gendirectcall(ll_tupleiter, citerptr, v_tuple) - - def rtype_next(self, hop): - v_iter, = hop.inputargs(self) - hop.has_implicit_exception(StopIteration) # record that we know about it - hop.exception_is_here() - v = hop.gendirectcall(ll_tuplenext, v_iter) - return hop.llops.convertvar(v, self.r_tuple.items_r[0], self.r_tuple.external_items_r[0]) - -def ll_tupleiter(ITERPTR, tuple): - iter = malloc(ITERPTR.TO) - iter.tuple = tuple - return iter - -def ll_tuplenext(iter): - # for iterating over length 1 tuples only! - t = iter.tuple - if t: - iter.tuple = nullptr(typeOf(t).TO) - return t.item0 - else: - raise StopIteration Modified: pypy/dist/pypy/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/dist/pypy/rpython/rtyper.py Fri Mar 24 10:32:40 2006 @@ -509,7 +509,7 @@ return rlist.rtype_alloc_and_set(hop) def translate_op_newtuple(self, hop): - return rtuple.rtype_newtuple(hop) + return self.type_system.rtuple.rtype_newtuple(hop) def translate_op_newslice(self, hop): return rslice.rtype_newslice(hop) @@ -835,7 +835,7 @@ from pypy.rpython import robject from pypy.rpython import rint, rbool, rfloat from pypy.rpython import rslice, rrange -from pypy.rpython import rlist, rstr, rtuple, rdict +from pypy.rpython import rlist, rstr, rdict from pypy.rpython import rclass, rbuiltin, rpbc, rspecialcase from pypy.rpython import rexternalobj from pypy.rpython import rptr Modified: pypy/dist/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rtuple.py (original) +++ pypy/dist/pypy/rpython/test/test_rtuple.py Fri Mar 24 10:32:40 2006 @@ -1,12 +1,12 @@ from pypy.translator.translator import TranslationContext from pypy.rpython.lltypesystem.lltype import * -from pypy.rpython.rtuple import * from pypy.rpython.rint import signed_repr from pypy.rpython.rbool import bool_repr from pypy.rpython.test.test_llinterp import interpret import py def test_rtuple(): + from pypy.rpython.lltypesystem.rtuple import TupleRepr rtuple = TupleRepr(None, [signed_repr, bool_repr]) assert rtuple.lowleveltype == Ptr(GcStruct('tuple2', ('item0', Signed), @@ -15,26 +15,31 @@ # ____________________________________________________________ -def test_simple(): - def dummyfn(x): - l = (10,x,30) - return l[2] - res = interpret(dummyfn,[4]) - assert res == 30 - -def test_len(): - def dummyfn(x): - l = (5,x) - return len(l) - res = interpret(dummyfn, [4]) - assert res == 2 - -def test_return_tuple(): - def dummyfn(x, y): - return (xy) - res = interpret(dummyfn, [4,5]) - assert res.item0 == True - assert res.item1 == False +class AbstractTestRTuple: + + def interpret(self, f, args): + return interpret(f, args, type_system=self.type_system) + + def test_simple(self): + def dummyfn(x): + l = (10,x,30) + return l[2] + res = self.interpret(dummyfn,[4]) + assert res == 30 + + def test_len(self): + def dummyfn(x): + l = (5,x) + return len(l) + res = self.interpret(dummyfn, [4]) + assert res == 2 + + def test_return_tuple(self): + def dummyfn(x, y): + return (xy) + res = self.interpret(dummyfn, [4,5]) + assert res.item0 == True + assert res.item1 == False def test_tuple_concatenation(): def f(n): @@ -208,3 +213,13 @@ res1 = interpret(f, [12, 27]) res2 = interpret(f, [27, 12]) assert res1 != res2 + + +class TestLLTuple(AbstractTestRTuple): + + type_system = "lltype" + +class TestOOTuple(AbstractTestRTuple): + + type_system = "ootype" + Modified: pypy/dist/pypy/rpython/typesystem.py ============================================================================== --- pypy/dist/pypy/rpython/typesystem.py (original) +++ pypy/dist/pypy/rpython/typesystem.py Fri Mar 24 10:32:40 2006 @@ -20,7 +20,7 @@ None, None, ['__doc__']) except ImportError: return None - if name in ('rclass', 'rpbc', 'rbuiltin', 'exceptiondata'): + if name in ('rclass', 'rpbc', 'rbuiltin', 'rtuple', 'exceptiondata'): mod = load(name) if mod is not None: setattr(self, name, mod) Modified: pypy/dist/pypy/translator/squeak/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/runtest.py (original) +++ pypy/dist/pypy/translator/squeak/test/runtest.py Fri Mar 24 10:32:40 2006 @@ -91,7 +91,7 @@ "variable to point to an image.") startup_st = self._write_startup() options = "-headless" - if conftest.option.showsqueak: + if hasattr(conftest, "showsqueak") and conftest.option.showsqueak: options = "" cmd = 'squeak %s -- %s %s "%s" %s' \ % (options, startup_st, udir.join(self._gen.filename), From mwh at codespeak.net Fri Mar 24 11:32:14 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 11:32:14 +0100 (CET) Subject: [pypy-svn] r24941 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324103214.37D8910151@code0.codespeak.net> Author: mwh Date: Fri Mar 24 11:32:12 2006 New Revision: 24941 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: o look, another lloperation Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 11:32:12 2006 @@ -288,6 +288,7 @@ 'hint': LLOp(), 'check_no_more_arg': LLOp(canraise=(Exception,)), 'decode_arg': LLOp(canraise=(Exception,)), + 'decode_arg_def': LLOp(canraise=(Exception,)), } # __________ operations on PyObjects __________ From mwh at codespeak.net Fri Mar 24 11:35:29 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 11:35:29 +0100 (CET) Subject: [pypy-svn] r24942 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324103529.F249110153@code0.codespeak.net> Author: mwh Date: Fri Mar 24 11:35:19 2006 New Revision: 24942 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: add 'float_pow' to the lloperation table Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 11:35:19 2006 @@ -175,6 +175,7 @@ 'float_ge': LLOp(canfold=True), 'float_floor': LLOp(canfold=True), 'float_fmod': LLOp(canfold=True), + 'float_pow': LLOp(canfold=True), 'llong_is_true': LLOp(canfold=True), 'llong_neg': LLOp(canfold=True), From mwh at codespeak.net Fri Mar 24 11:52:56 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 11:52:56 +0100 (CET) Subject: [pypy-svn] r24943 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324105256.2500210156@code0.codespeak.net> Author: mwh Date: Fri Mar 24 11:52:55 2006 New Revision: 24943 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: some more operations! weee! Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 11:52:55 2006 @@ -127,7 +127,11 @@ 'int_and_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_or_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_lshift_ovf': LLOp(canfold=True, canraise=(OverflowError,)), + 'int_lshift_val': LLOp(canfold=True, canraise=(ValueError,)), + 'int_lshift_ovf_val': LLOp(canfold=True, canraise=(OverflowError, ValueError,)), 'int_rshift_ovf': LLOp(canfold=True, canraise=(OverflowError,)), + 'int_rshift_val': LLOp(canfold=True, canraise=(ValueError,)), + 'int_rshift_ovf_val': LLOp(canfold=True, canraise=(OverflowError, ValueError,)), 'int_xor_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_floordiv_ovf_zer': LLOp(canfold=True, canraise=(OverflowError, ZeroDivisionError)), 'int_mod_ovf_zer': LLOp(canfold=True, canraise=(OverflowError, ZeroDivisionError)), @@ -141,8 +145,11 @@ 'uint_sub': LLOp(canfold=True), 'uint_mul': LLOp(canfold=True), 'uint_div': LLOp(canfold=True), + 'uint_div_zer': LLOp(canfold=True, canraise=(ZeroDivisionError,)), 'uint_truediv': LLOp(canfold=True), + 'uint_truediv_zer': LLOp(canfold=True, canraise=(ZeroDivisionError,)), 'uint_floordiv': LLOp(canfold=True), + 'uint_floordiv_zer': LLOp(canfold=True, canraise=(ZeroDivisionError,)), 'uint_mod': LLOp(canfold=True), 'uint_lt': LLOp(canfold=True), 'uint_le': LLOp(canfold=True), From mwh at codespeak.net Fri Mar 24 12:01:23 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 12:01:23 +0100 (CET) Subject: [pypy-svn] r24944 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060324110123.35F541015A@code0.codespeak.net> Author: mwh Date: Fri Mar 24 12:01:17 2006 New Revision: 24944 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: make this test a little tiny bit less fraile Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Fri Mar 24 12:01:17 2006 @@ -70,7 +70,6 @@ one(0) one(1) t, g = transform_func(foo, []) - assert len(list(g.iterblocks())) == 4 f = compile_func(foo, []) py.test.raises(ValueError, f) From cfbolz at codespeak.net Fri Mar 24 12:04:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 24 Mar 2006 12:04:22 +0100 (CET) Subject: [pypy-svn] r24945 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324110422.36B2F1015A@code0.codespeak.net> Author: cfbolz Date: Fri Mar 24 12:04:21 2006 New Revision: 24945 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: (mwh, abusing carl's screen + clean checkout on snake :) add error values for long long types. Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 12:04:21 2006 @@ -6,10 +6,12 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.memory.lladdress import NULL from pypy.rpython import rclass -from pypy.rpython.rarithmetic import r_uint +from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong PrimitiveErrorValue = {lltype.Signed: -1, lltype.Unsigned: r_uint(-1), + lltype.SignedLongLong: r_longlong(-1), + lltype.UnsignedLongLong: r_ulonglong(-1), lltype.Float: -1.0, lltype.Char: chr(255), lltype.Bool: True, From mwh at codespeak.net Fri Mar 24 12:17:22 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 12:17:22 +0100 (CET) Subject: [pypy-svn] r24946 - in pypy/branch/explicit-exceptions/translator/c: . src Message-ID: <20060324111722.38D2210155@code0.codespeak.net> Author: mwh Date: Fri Mar 24 12:17:17 2006 New Revision: 24946 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py pypy/branch/explicit-exceptions/translator/c/extfunc.py pypy/branch/explicit-exceptions/translator/c/funcgen.py pypy/branch/explicit-exceptions/translator/c/gc.py pypy/branch/explicit-exceptions/translator/c/src/exception.h pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h pypy/branch/explicit-exceptions/translator/c/src/main.h pypy/branch/explicit-exceptions/translator/c/src/mem.h Log: implement all the RPyExceptionOccurred(), etc functions in RPython so that instead of having to special case exceptions all over the place, the existing machinery can do it for us, and in fact this reduces the overall number of special cases somewhat. this status of the branch is that one test fails in test_backendoptimized (test_del_inheritance, a bit of a mystery), test_boehm, test_standalone and test_exceptiontransform pass, test_stackless crashes and the others i haven't run recently. not too bad :) Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 12:17:17 2006 @@ -7,6 +7,8 @@ from pypy.rpython.memory.lladdress import NULL from pypy.rpython import rclass from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong +from pypy.annotation import model as annmodel +from pypy.rpython.annlowlevel import MixLevelHelperAnnotator PrimitiveErrorValue = {lltype.Signed: -1, lltype.Unsigned: r_uint(-1), @@ -25,63 +27,88 @@ return Constant(lltype.nullptr(T.TO), T) assert 0, "not implemented yet" -# dummy functions to make the resulting graphs runnable on the llinterpreter - -class ExcData(object): - exc_type = None - exc_value = None - -def rpyexc_occured(): - return ExcData.exc_type is not None - -def rpyexc_fetch_type(): - return ExcData.exc_type - -def rpyexc_fetch_value(): - return ExcData.exc_value - -def rpyexc_clear(): - ExcData.exc_type = None - ExcData.exc_value = None - -def rpyexc_raise(etype, evalue): - ExcData.exc_type = etype - ExcData.exc_value = evalue - class ExceptionTransformer(object): def __init__(self, translator): self.translator = translator self.raise_analyzer = canraise.RaiseAnalyzer(translator) self.exc_data = translator.rtyper.getexceptiondata() + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + l2a = annmodel.lltype_to_annotation + + class ExcData(object): + pass + #exc_type = lltype.nullptr(self.exc_data.lltype_of_exception_type.TO) + #exc_value = lltype.nullptr(self.exc_data.lltype_of_exception_value.TO) + + exc_data = ExcData() + null_type = lltype.nullptr(self.exc_data.lltype_of_exception_type.TO) + null_value = lltype.nullptr(self.exc_data.lltype_of_exception_value.TO) + + def rpyexc_occured(): + return exc_data.exc_type is not null_type + + def rpyexc_fetch_type(): + return exc_data.exc_type + + def rpyexc_fetch_value(): + return exc_data.exc_value + + def rpyexc_clear(): + exc_data.exc_type = null_type + exc_data.exc_value = null_value + + def rpyexc_raise(etype, evalue): + # assert(!RPyExceptionOccurred()); + exc_data.exc_type = etype + exc_data.exc_value = evalue + RPYEXC_OCCURED_TYPE = lltype.FuncType([], lltype.Bool) + rpyexc_occured_graph = mixlevelannotator.getgraph( + rpyexc_occured, [], l2a(lltype.Bool)) self.rpyexc_occured_ptr = Constant(lltype.functionptr( - RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", external="C", - neverrraises=True, _callable=rpyexc_occured), + RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", + graph=rpyexc_occured_graph), lltype.Ptr(RPYEXC_OCCURED_TYPE)) + RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_type) + rpyexc_fetch_type_graph = mixlevelannotator.getgraph( + rpyexc_fetch_type, [], + l2a(self.exc_data.lltype_of_exception_type)) self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr( - RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", external="C", - neverraises=True, _callable=rpyexc_fetch_type), + RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", + graph=rpyexc_fetch_type_graph), lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE)) + RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_value) + rpyexc_fetch_value_graph = mixlevelannotator.getgraph( + rpyexc_fetch_value, [], + l2a(self.exc_data.lltype_of_exception_value)) self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr( - RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", external="C", - neverraises=True, _callable=rpyexc_fetch_value), + RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", + graph=rpyexc_fetch_value_graph), lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE)) + RPYEXC_CLEAR = lltype.FuncType([], lltype.Void) + rpyexc_clear_graph = mixlevelannotator.getgraph( + rpyexc_clear, [], l2a(lltype.Void)) self.rpyexc_clear_ptr = Constant(lltype.functionptr( - RPYEXC_CLEAR, "RPyClearException", external="C", - neverraises=True, _callable=rpyexc_clear), + RPYEXC_CLEAR, "RPyClearException", + graph=rpyexc_clear_graph), lltype.Ptr(RPYEXC_CLEAR)) + RPYEXC_RAISE = lltype.FuncType([self.exc_data.lltype_of_exception_type, self.exc_data.lltype_of_exception_value], lltype.Void) - # XXX cannot really be called as a normal function, it wants to steal - # the argument references away, so those should not be pop_alive (decrefed) + rpyexc_raise_graph = mixlevelannotator.getgraph( + rpyexc_raise, [l2a(self.exc_data.lltype_of_exception_type), + l2a(self.exc_data.lltype_of_exception_value)], + l2a(lltype.Void)) self.rpyexc_raise_ptr = Constant(lltype.functionptr( - RPYEXC_RAISE, "RPyRaiseException", external="C", - neverraises=True, _callable=rpyexc_raise), + RPYEXC_RAISE, "RPyRaiseException", + graph=rpyexc_raise_graph), lltype.Ptr(RPYEXC_RAISE)) + + mixlevelannotator.finish() def transform_completely(self): for graph in self.translator.graphs: Modified: pypy/branch/explicit-exceptions/translator/c/extfunc.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/extfunc.py (original) +++ pypy/branch/explicit-exceptions/translator/c/extfunc.py Fri Mar 24 12:17:17 2006 @@ -226,6 +226,7 @@ def predeclare_exception_data(db, rtyper, optimize=True): # Exception-related types and constants exceptiondata = rtyper.getexceptiondata() + exctransformer = db.exctransformer yield ('RPYTHON_EXCEPTION_VTABLE', exceptiondata.lltype_of_exception_type) yield ('RPYTHON_EXCEPTION', exceptiondata.lltype_of_exception_value) @@ -236,6 +237,12 @@ if not db.standalone: yield ('RPYTHON_PYEXCCLASS2EXC', exceptiondata.fn_pyexcclass2exc) + yield ('RPyExceptionOccurred', exctransformer.rpyexc_occured_ptr.value) + yield ('RPyFetchExceptionType', exctransformer.rpyexc_fetch_type_ptr.value) + yield ('RPyFetchExceptionValue', exctransformer.rpyexc_fetch_value_ptr.value) + yield ('RPyClearException', exctransformer.rpyexc_clear_ptr.value) + yield ('RPyRaiseException', exctransformer.rpyexc_raise_ptr.value) + for pyexccls in exceptiondata.standardexceptions: exc_llvalue = exceptiondata.fn_pyexcclass2exc( lltype.pyobjectptr(pyexccls)) Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Fri Mar 24 12:17:17 2006 @@ -189,10 +189,9 @@ assert len(block.inputargs) == 1 # regular return block if self.cpython_exc: - # XXX leaks! assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr yield 'if (RPyExceptionOccurred()) {' - yield '\tRPyConvertExceptionToCPython(rpython_exc_value);' + yield '\tRPyConvertExceptionToCPython();' yield '\treturn NULL;' yield '}' retval = self.expr(block.inputargs[0]) Modified: pypy/branch/explicit-exceptions/translator/c/gc.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/gc.py (original) +++ pypy/branch/explicit-exceptions/translator/c/gc.py Fri Mar 24 12:17:17 2006 @@ -118,15 +118,12 @@ def OP_GC_FETCH_EXCEPTION(self, funcgen, op, err): result = funcgen.expr(op.result) - return ('%s = rpython_exc_value;\n' - 'rpython_exc_type = NULL;\n' - 'rpython_exc_value = NULL;') % (result, ) + return ('%s = RPyFetchExceptionValue();\n' + 'RPyClearException();') % (result, ) def OP_GC_RESTORE_EXCEPTION(self, funcgen, op, err): argh = funcgen.expr(op.args[0]) - # XXX uses officially bad fishing - # see src/exception.h - return 'if (%s != NULL) RPyRaiseException(%s->o_typeptr, %s);' % (argh, argh, argh) + return 'if (%s != NULL) RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(%s), %s);' % (argh, argh, argh) def OP_GC__COLLECT(self, funcgen, op, err): return '' @@ -223,15 +220,12 @@ def OP_GC_FETCH_EXCEPTION(self, funcgen, op, err): result = funcgen.expr(op.result) - return ('%s = rpython_exc_value;\n' - 'rpython_exc_type = NULL;\n' - 'rpython_exc_value = NULL;') % (result, ) + return ('%s = RPyFetchExceptionValue();\n' + 'RPyClearException();') % (result, ) def OP_GC_RESTORE_EXCEPTION(self, funcgen, op, err): argh = funcgen.expr(op.args[0]) - # XXX uses officially bad fishing - # see src/exception.h - return 'if (%s != NULL) RPyRaiseException(%s->o_typeptr, %s);' % (argh, argh, argh) + return 'if (%s != NULL) RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(%s), %s);' % (argh, argh, argh) def OP_GC__COLLECT(self, funcgen, op, err): return 'GC_gcollect(); GC_invoke_finalizers();' Modified: pypy/branch/explicit-exceptions/translator/c/src/exception.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/exception.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/exception.h Fri Mar 24 12:17:17 2006 @@ -10,44 +10,12 @@ #ifdef HAVE_RTYPER /* RPython version of exceptions */ /******************************************************************/ -#ifdef PYPY_NOT_MAIN_FILE -extern RPYTHON_EXCEPTION_VTABLE rpython_exc_type; -extern RPYTHON_EXCEPTION rpython_exc_value; -#else -RPYTHON_EXCEPTION_VTABLE rpython_exc_type = NULL; -RPYTHON_EXCEPTION rpython_exc_value = NULL; -#endif - -#define RPyExceptionOccurred() (rpython_exc_type != NULL) - -#define RPyRaiseException(etype, evalue) do { \ - assert(!RPyExceptionOccurred()); \ - rpython_exc_type = etype; \ - rpython_exc_value = evalue; \ - } while (0) - #define RPyFetchException(etypevar, evaluevar, type_of_evaluevar) do { \ - etypevar = rpython_exc_type; \ - evaluevar = (type_of_evaluevar) rpython_exc_value; \ - rpython_exc_type = NULL; \ - rpython_exc_value = NULL; \ - } while (0) - -#define RPyFetchExceptionValue() rpython_exc_value - -#define RPyFetchExceptionType() rpython_exc_type - -#define RPyClearException() do { \ - rpython_exc_type = NULL; \ - rpython_exc_value = NULL; \ + etypevar = RPyFetchExceptionType(); \ + evaluevar = (type_of_evaluevar)RPyFetchExceptionValue(); \ + RPyClearException(); \ } while (0) - - -#define RPyMatchException(etype) RPYTHON_EXCEPTION_MATCH(rpython_exc_type, \ - (RPYTHON_EXCEPTION_VTABLE) etype) - - /* prototypes */ #define RPyRaiseSimpleException(exc, msg) _RPyRaiseSimpleException(R##exc) @@ -55,26 +23,17 @@ #ifndef PYPY_STANDALONE void RPyConvertExceptionFromCPython(void); -void _RPyConvertExceptionToCPython(void); -#define RPyConvertExceptionToCPython(vanishing) \ - _RPyConvertExceptionToCPython(); \ - vanishing = rpython_exc_value; \ - rpython_exc_type = NULL; \ - rpython_exc_value = NULL +void RPyConvertExceptionToCPython(void); #endif - /* implementations */ #ifndef PYPY_NOT_MAIN_FILE void _RPyRaiseSimpleException(RPYTHON_EXCEPTION rexc) { - /* XXX 1. uses officially bad fishing */ - /* XXX 2. msg is ignored */ - rpython_exc_type = rexc->o_typeptr; - rpython_exc_value = rexc; - PUSH_ALIVE(rpython_exc_value); + /* XXX msg is ignored */ + RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(rexc), rexc); } #ifndef PYPY_STANDALONE @@ -82,15 +41,18 @@ { /* convert the CPython exception to an RPython one */ PyObject *exc_type, *exc_value, *exc_tb; + RPYTHON_EXCEPTION rexc; + assert(PyErr_Occurred()); assert(!RPyExceptionOccurred()); PyErr_Fetch(&exc_type, &exc_value, &exc_tb); - /* XXX loosing the error message here */ - rpython_exc_value = RPYTHON_PYEXCCLASS2EXC(exc_type); - rpython_exc_type = RPYTHON_TYPE_OF_EXC_INST(rpython_exc_value); + + /* XXX losing the error message here */ + rexc = RPYTHON_PYEXCCLASS2EXC(exc_type); + RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(rexc), rexc); } -void _RPyConvertExceptionToCPython(void) +void RPyConvertExceptionToCPython(void) { /* XXX 1. uses officially bad fishing */ /* XXX 2. looks for exception classes by name, fragile */ @@ -98,7 +60,7 @@ PyObject* pycls; assert(RPyExceptionOccurred()); assert(!PyErr_Occurred()); - clsname = rpython_exc_type->ov_name->items; + clsname = RPyFetchExceptionType()->ov_name->items; pycls = PyDict_GetItemString(PyEval_GetBuiltins(), clsname); if (pycls != NULL && PyClass_Check(pycls) && PyClass_IsSubclass(pycls, PyExc_Exception)) { @@ -107,6 +69,7 @@ else { PyErr_SetString(RPythonError, clsname); } + RPyClearException(); } #endif /* !PYPY_STANDALONE */ @@ -129,7 +92,6 @@ } \ Py_XDECREF(__tb); \ } while (0) -#define RPyMatchException(etype) PyErr_ExceptionMatches(etype) #define RPyConvertExceptionFromCPython() /* nothing */ #define RPyConvertExceptionToCPython(vanishing) vanishing = NULL Modified: pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h Fri Mar 24 12:17:17 2006 @@ -17,6 +17,7 @@ #undef USE_OPTIMIZED_STACKLESS_UNWIND /* XXX we seem to be missing something */ +/* XXX also now very broken because exceptions have changed */ #ifdef USE_OPTIMIZED_STACKLESS_UNWIND Modified: pypy/branch/explicit-exceptions/translator/c/src/main.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/main.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/main.h Fri Mar 24 12:17:17 2006 @@ -35,7 +35,7 @@ if (RPyExceptionOccurred()) { /* fish for the exception type, at least */ fprintf(stderr, "Fatal PyPy error: %s\n", - rpython_exc_type->ov_name->items); + RPyFetchExceptionType()->ov_name->items); exitcode = 1; } return exitcode; Modified: pypy/branch/explicit-exceptions/translator/c/src/mem.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/mem.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/mem.h Fri Mar 24 12:17:17 2006 @@ -29,9 +29,6 @@ #define OP_FREE(p) { PyObject_Free(p); COUNT_FREE; } -/* XXX uses officially bad fishing */ -#define PUSH_ALIVE(obj) obj->refcount++ - /*------------------------------------------------------------*/ #ifndef COUNT_OP_MALLOCS /*------------------------------------------------------------*/ @@ -82,9 +79,6 @@ */ #define OP_CALL_BOEHM_GC_ALLOC(size, r, err) OP_BOEHM_ZERO_MALLOC(size, r, 0, 0, err) -#undef PUSH_ALIVE -#define PUSH_ALIVE(obj) - #endif /* USING_BOEHM_GC */ /* for no GC */ From mwh at codespeak.net Fri Mar 24 13:02:47 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 13:02:47 +0100 (CET) Subject: [pypy-svn] r24949 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324120247.8CC2810145@code0.codespeak.net> Author: mwh Date: Fri Mar 24 13:02:46 2006 New Revision: 24949 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: mumble mumble 'yield_current_frame_to_caller' mumble mumble lloperation mumble mumble hope this one can't raise... Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 13:02:46 2006 @@ -289,6 +289,10 @@ 'gc_protect': LLOp(), 'gc_unprotect': LLOp(), + # __________ stackless operation(s) __________ + + 'yield_current_frame_to_caller': LLOp(), + # __________ misc operations __________ 'keepalive': LLOp(), From mwh at codespeak.net Fri Mar 24 13:05:33 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 13:05:33 +0100 (CET) Subject: [pypy-svn] r24951 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324120533.CAC3F10145@code0.codespeak.net> Author: mwh Date: Fri Mar 24 13:05:27 2006 New Revision: 24951 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py pypy/branch/explicit-exceptions/translator/c/funcgen.py Log: small changes to make stackless work again. slightly hackish, stackless is getting slightly 'old-fashioned' in a pypy sense, it should probably be done as a graph transformation or something. still works though... Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 13:05:27 2006 @@ -211,6 +211,9 @@ startblock = Block(inputargs) startblock.operations.append(newop) newgraph = FunctionGraph("dummy_exc1", startblock) + # XXX this is makes stackless happier, for very bad reasons. + # XXX do something about this. + newgraph.func = None startblock.closeblock(Link([result], newgraph.returnblock)) startblock.exits = list(startblock.exits) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Fri Mar 24 13:05:27 2006 @@ -347,6 +347,9 @@ # skip assignment of 'void' return value r = self.expr(op.result) line = '%s = %s' % (r, line) + check = self.check_directcall_result(op, err) + if check: + return line + '\n' + check return line # the following works since the extra arguments that indirect_call has @@ -354,7 +357,7 @@ OP_INDIRECT_CALL = OP_DIRECT_CALL def check_directcall_result(self, op, err): - return 'if (RPyExceptionOccurred())\n\tFAIL(%s);' % err + return None # low-level operations def generic_get(self, op, sourceexpr): From mwh at codespeak.net Fri Mar 24 13:51:39 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 13:51:39 +0100 (CET) Subject: [pypy-svn] r24954 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324125139.291721013D@code0.codespeak.net> Author: mwh Date: Fri Mar 24 13:51:32 2006 New Revision: 24954 Modified: pypy/branch/explicit-exceptions/translator/c/database.py pypy/branch/explicit-exceptions/translator/c/funcgen.py Log: some very thin paper over what happens when there's no rtyper, or even translator. enough to get test_database to pass, absolutely not enough for test_annotated. Modified: pypy/branch/explicit-exceptions/translator/c/database.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/database.py (original) +++ pypy/branch/explicit-exceptions/translator/c/database.py Fri Mar 24 13:51:32 2006 @@ -39,7 +39,10 @@ if gcpolicy is None: from pypy.translator.c import gc gcpolicy = gc.RefcountingGcPolicy - self.exctransformer = ExceptionTransformer(translator) + if translator is None or translator.rtyper is None: + self.exctransformer = None + else: + self.exctransformer = ExceptionTransformer(translator) self.gcpolicy = gcpolicy(self, thread_enabled) self.gctransformer = gcpolicy.transformerclass(translator) self.completed = False Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Fri Mar 24 13:51:32 2006 @@ -37,7 +37,8 @@ self.cpython_exc = cpython_exc self.functionname = functionname # apply the exception transformation - self.db.exctransformer.create_exception_handling(self.graph) + if self.db.exctransformer: + self.db.exctransformer.create_exception_handling(self.graph) # apply the gc transformation self.db.gctransformer.transform_graph(self.graph) #self.graph.show() From mwh at codespeak.net Fri Mar 24 13:57:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 13:57:15 +0100 (CET) Subject: [pypy-svn] r24955 - pypy/branch/explicit-exceptions/translator/c/src Message-ID: <20060324125715.6F5131013D@code0.codespeak.net> Author: mwh Date: Fri Mar 24 13:57:13 2006 New Revision: 24955 Modified: pypy/branch/explicit-exceptions/translator/c/src/ll__socket.h Log: setipaddr already sets an exception, so don't set another in LL__socket_connect when it returns -1. the failure mode is a bit worrying: a segfault. i think this has to do with the fact that the helper C code does not own all references it manipulates. Modified: pypy/branch/explicit-exceptions/translator/c/src/ll__socket.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/ll__socket.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/ll__socket.h Fri Mar 24 13:57:13 2006 @@ -116,8 +116,6 @@ if (setipaddr(RPyString_AsString(sockname->t_item0), (struct sockaddr *) &addr, sizeof(addr), family) < 0) { - // XXX we actually want to raise socket.error - RPYTHON_RAISE_OSERROR(errno); return NULL; } From arigo at codespeak.net Fri Mar 24 14:15:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Mar 2006 14:15:29 +0100 (CET) Subject: [pypy-svn] r24956 - pypy/dist/pypy/module/thread/test Message-ID: <20060324131529.6276810141@code0.codespeak.net> Author: arigo Date: Fri Mar 24 14:15:27 2006 New Revision: 24956 Modified: pypy/dist/pypy/module/thread/test/support.py pypy/dist/pypy/module/thread/test/test_local.py pypy/dist/pypy/module/thread/test/test_thread.py Log: Adapted the thread tests to run nice'd on a busy server, by increasing the timeouts to 5 minutes. Now that they generally work, they should not timeout. You can decrease the value in support.py again for interactive py.test debugging. Modified: pypy/dist/pypy/module/thread/test/support.py ============================================================================== --- pypy/dist/pypy/module/thread/test/support.py (original) +++ pypy/dist/pypy/module/thread/test/support.py Fri Mar 24 14:15:27 2006 @@ -4,14 +4,16 @@ from pypy.interpreter.gateway import ObjSpace, W_Root, interp2app_temp -def waitfor(space, w_condition, timeout=10.0): +def waitfor(space, w_condition, timeout=300.0): w_sleep = space.appexec([], "():\n import time; return time.sleep") + adaptivedelay = 0.04 limit = time.time() + timeout while time.time() <= limit: - space.call_function(w_sleep, space.wrap(0.04)) + space.call_function(w_sleep, space.wrap(adaptivedelay)) gc.collect() if space.is_true(space.call_function(w_condition)): return + adaptivedelay *= 1.05 print '*** timed out ***' waitfor.unwrap_spec = [ObjSpace, W_Root, float] Modified: pypy/dist/pypy/module/thread/test/test_local.py ============================================================================== --- pypy/dist/pypy/module/thread/test/test_local.py (original) +++ pypy/dist/pypy/module/thread/test/test_local.py Fri Mar 24 14:15:27 2006 @@ -32,7 +32,7 @@ ok.append(success) for i in range(20): thread.start_new_thread(f, (i,)) - self.waitfor(lambda: len(ok) == 20, timeout=30.0) + self.waitfor(lambda: len(ok) == 20) #, timeout=30.0) assert ok == 20*[True] # see stdout/stderr for failures in the threads self.waitfor(lambda: len(freed) >= 40) @@ -62,7 +62,7 @@ seen.append(x.tag) for i in range(5): thread.start_new_thread(f, ()) - self.waitfor(lambda: len(seen) == 5, timeout=20.0) + self.waitfor(lambda: len(seen) == 5) #, timeout=20.0) seen1 = seen[:] seen1.sort() assert seen1 == [1, 2, 3, 4, 5] @@ -82,5 +82,5 @@ done.append(1) for i in range(5): thread.start_new_thread(f, (i,)) - self.waitfor(lambda: len(done) == 5, timeout=20.0) + self.waitfor(lambda: len(done) == 5) #, timeout=20.0) assert len(done) == 5 Modified: pypy/dist/pypy/module/thread/test/test_thread.py ============================================================================== --- pypy/dist/pypy/module/thread/test/test_thread.py (original) +++ pypy/dist/pypy/module/thread/test/test_thread.py Fri Mar 24 14:15:27 2006 @@ -139,6 +139,6 @@ thread.start_new_thread(f, (i, done)) done_marker.append(done) for done in done_marker: - self.waitfor(lambda: done, timeout=30.0) + self.waitfor(lambda: done) #, timeout=30.0) assert done # see stderr for failures in threads assert sorted(lst) == range(120) From nik at codespeak.net Fri Mar 24 14:50:47 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 24 Mar 2006 14:50:47 +0100 (CET) Subject: [pypy-svn] r24961 - in pypy/dist/pypy: jit rpython rpython/lltypesystem rpython/ootypesystem rpython/test Message-ID: <20060324135047.ED39F1012A@code0.codespeak.net> Author: nik Date: Fri Mar 24 14:50:45 2006 New Revision: 24961 Modified: pypy/dist/pypy/jit/hinttimeshift.py pypy/dist/pypy/rpython/lltypesystem/rtuple.py pypy/dist/pypy/rpython/ootypesystem/rtuple.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: make more tuple tests pass on ootypesystem. share more code between lltype/ootype rtuple. pleasant surprise, much of the implementation will be shared in the end. Modified: pypy/dist/pypy/jit/hinttimeshift.py ============================================================================== --- pypy/dist/pypy/jit/hinttimeshift.py (original) +++ pypy/dist/pypy/jit/hinttimeshift.py Fri Mar 24 14:50:45 2006 @@ -310,7 +310,7 @@ s_key_tuple = annmodel.SomeTuple(items_s) r_key = getrepr(s_key_tuple) r_key.setup() - v_key = rtuple.newtuple(llops, r_key, key_v) + v_key = rtuple.TupleRepr.newtuple(llops, r_key, key_v) v_oldjitstate = newinputargs[0] Modified: pypy/dist/pypy/rpython/lltypesystem/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rtuple.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rtuple.py Fri Mar 24 14:50:45 2006 @@ -85,8 +85,17 @@ fields = zip(self.fieldnames, self.lltypes) self.lowleveltype = Ptr(GcStruct('tuple%d' % len(self.items_r), *fields)) - def compact_repr(self): - return "TupleR %s" % ' '.join([llt._short_name() for llt in self.lltypes]) + def newtuple(cls, llops, r_tuple, items_v): + # items_v should have the lowleveltype of the internal reprs + if len(r_tuple.items_r) == 0: + return inputconst(r_tuple, ()) # always the same empty tuple + c1 = inputconst(Void, r_tuple.lowleveltype.TO) + v_result = llops.genop('malloc', [c1], resulttype = r_tuple.lowleveltype) + for i in range(len(r_tuple.items_r)): + cname = inputconst(Void, r_tuple.fieldnames[i]) + llops.genop('setfield', [v_result, cname, items_v[i]]) + return v_result + newtuple = classmethod(newtuple) def instantiate(self): return malloc(self.lowleveltype.TO) @@ -130,80 +139,8 @@ return llops.genop('getfield', [v_tuple, cname], resulttype = llresult) - -class __extend__(pairtype(TupleRepr, Repr)): - def rtype_contains((r_tup, r_item), hop): - s_tup = hop.args_s[0] - if not s_tup.is_constant(): - raise TyperError("contains() on non-const tuple") - t = s_tup.const - typ = type(t[0]) - for x in t[1:]: - if type(x) is not typ: - raise TyperError("contains() on mixed-type tuple " - "constant %r" % (t,)) - d = {} - for x in t: - d[x] = None - hop2 = hop.copy() - _, _ = hop2.r_s_popfirstarg() - v_dict = Constant(d) - s_dict = hop.rtyper.annotator.bookkeeper.immutablevalue(d) - hop2.v_s_insertfirstarg(v_dict, s_dict) - return hop2.dispatch() - -class __extend__(pairtype(TupleRepr, TupleRepr)): - - def rtype_add((r_tup1, r_tup2), hop): - v_tuple1, v_tuple2 = hop.inputargs(r_tup1, r_tup2) - vlist = [] - for i in range(len(r_tup1.items_r)): - vlist.append(r_tup1.getitem(hop.llops, v_tuple1, i)) - for i in range(len(r_tup2.items_r)): - vlist.append(r_tup2.getitem(hop.llops, v_tuple2, i)) - return newtuple_cached(hop, vlist) - rtype_inplace_add = rtype_add - - def convert_from_to((r_from, r_to), v, llops): - if len(r_from.items_r) == len(r_to.items_r): - if r_from.lowleveltype == r_to.lowleveltype: - return v - n = len(r_from.items_r) - items_v = [] - for i in range(n): - item_v = r_from.getitem(llops, v, i) - item_v = llops.convertvar(item_v, - r_from.items_r[i], - r_to.items_r[i]) - items_v.append(item_v) - return newtuple(llops, r_to, items_v) - return NotImplemented - -# ____________________________________________________________ -# -# Irregular operations. - -def newtuple(llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs - if len(r_tuple.items_r) == 0: - return inputconst(r_tuple, ()) # always the same empty tuple - c1 = inputconst(Void, r_tuple.lowleveltype.TO) - v_result = llops.genop('malloc', [c1], resulttype = r_tuple.lowleveltype) - for i in range(len(r_tuple.items_r)): - cname = inputconst(Void, r_tuple.fieldnames[i]) - llops.genop('setfield', [v_result, cname, items_v[i]]) - return v_result - -def newtuple_cached(hop, items_v): - r_tuple = hop.r_result - if hop.s_result.is_constant(): - return inputconst(r_tuple, hop.s_result.const) - else: - return newtuple(hop.llops, r_tuple, items_v) - def rtype_newtuple(hop): - r_tuple = hop.r_result - vlist = hop.inputargs(*r_tuple.items_r) - return newtuple_cached(hop, vlist) + return TupleRepr._rtype_newtuple(hop) # # _________________________ Conversions _________________________ @@ -218,7 +155,7 @@ v_converted = llops.convertvar(v_item, pyobj_repr, r_to.items_r[i]) vlist.append(v_converted) - return newtuple(llops, r_to, vlist) + return r_to.newtuple(llops, r_to, vlist) class __extend__(pairtype(TupleRepr, PyObjRepr)): def convert_from_to((r_from, r_to), v, llops): Modified: pypy/dist/pypy/rpython/ootypesystem/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rtuple.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rtuple.py Fri Mar 24 14:50:45 2006 @@ -13,6 +13,18 @@ AbstractTupleRepr.__init__(self, rtyper, items_r) self.lowleveltype = tuple_type(self.fieldnames, self.lltypes) + def newtuple(cls, llops, r_tuple, items_v): + # items_v should have the lowleveltype of the internal reprs + if len(r_tuple.items_r) == 0: + return inputconst(r_tuple, ()) # always the same empty tuple + c1 = inputconst(ootype.Void, r_tuple.lowleveltype) + v_result = llops.genop("new", [c1], resulttype=r_tuple.lowleveltype) + for i in range(len(r_tuple.items_r)): + cname = inputconst(ootype.Void, r_tuple.fieldnames[i]) + llops.genop("oosetfield", [v_result, cname, items_v[i]]) + return v_result + newtuple = classmethod(newtuple) + def instantiate(self): return ootype.new(self.lowleveltype) @@ -22,6 +34,10 @@ cname = inputconst(ootype.Void, name) return llops.genop("oogetfield", [v_tuple, cname], resulttype=llresult) + def rtype_id(self, hop): + vinst, = hop.inputargs(self) + return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed) + _tuple_types = {} @@ -34,29 +50,8 @@ INST = ootype.Instance("Tuple%s" % len(fieldnames), ootype.ROOT, fields) _tuple_types[key] = INST return INST -# ____________________________________________________________ -# -# Irregular operations. - -def newtuple(llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs - if len(r_tuple.items_r) == 0: - return inputconst(r_tuple, ()) # always the same empty tuple - c1 = inputconst(ootype.Void, r_tuple.lowleveltype) - v_result = llops.genop("new", [c1], resulttype=r_tuple.lowleveltype) - for i in range(len(r_tuple.items_r)): - cname = inputconst(ootype.Void, r_tuple.fieldnames[i]) - llops.genop("oosetfield", [v_result, cname, items_v[i]]) - return v_result - -def newtuple_cached(hop, items_v): - r_tuple = hop.r_result - if hop.s_result.is_constant(): - return inputconst(r_tuple, hop.s_result.const) - else: - return newtuple(hop.llops, r_tuple, items_v) + def rtype_newtuple(hop): - r_tuple = hop.r_result - vlist = hop.inputargs(*r_tuple.items_r) - return newtuple_cached(hop, vlist) + return TupleRepr._rtype_newtuple(hop) Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Fri Mar 24 14:50:45 2006 @@ -34,6 +34,20 @@ self.lltypes = [r.lowleveltype for r in items_r] self.tuple_cache = {} + def newtuple_cached(cls, hop, items_v): + r_tuple = hop.r_result + if hop.s_result.is_constant(): + return inputconst(r_tuple, hop.s_result.const) + else: + return cls.newtuple(hop.llops, r_tuple, items_v) + newtuple_cached = classmethod(newtuple_cached) + + def _rtype_newtuple(cls, hop): + r_tuple = hop.r_result + vlist = hop.inputargs(*r_tuple.items_r) + return cls.newtuple_cached(hop, vlist) + _rtype_newtuple = classmethod(_rtype_newtuple) + def convert_const(self, value): assert isinstance(value, tuple) and len(value) == len(self.items_r) key = tuple([Constant(item) for item in value]) @@ -46,6 +60,9 @@ setattr(p, name, r.convert_const(obj)) return p + def compact_repr(self): + return "TupleR %s" % ' '.join([llt._short_name() for llt in self.lltypes]) + def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) @@ -60,3 +77,51 @@ v = r_tup.getitem(hop.llops, v_tuple, index) return hop.llops.convertvar(v, r_tup.items_r[index], r_tup.external_items_r[index]) +class __extend__(pairtype(AbstractTupleRepr, Repr)): + def rtype_contains((r_tup, r_item), hop): + s_tup = hop.args_s[0] + if not s_tup.is_constant(): + raise TyperError("contains() on non-const tuple") + t = s_tup.const + typ = type(t[0]) + for x in t[1:]: + if type(x) is not typ: + raise TyperError("contains() on mixed-type tuple " + "constant %r" % (t,)) + d = {} + for x in t: + d[x] = None + hop2 = hop.copy() + _, _ = hop2.r_s_popfirstarg() + v_dict = Constant(d) + s_dict = hop.rtyper.annotator.bookkeeper.immutablevalue(d) + hop2.v_s_insertfirstarg(v_dict, s_dict) + return hop2.dispatch() + +class __extend__(pairtype(AbstractTupleRepr, AbstractTupleRepr)): + + def rtype_add((r_tup1, r_tup2), hop): + v_tuple1, v_tuple2 = hop.inputargs(r_tup1, r_tup2) + vlist = [] + for i in range(len(r_tup1.items_r)): + vlist.append(r_tup1.getitem(hop.llops, v_tuple1, i)) + for i in range(len(r_tup2.items_r)): + vlist.append(r_tup2.getitem(hop.llops, v_tuple2, i)) + return r_tup1.newtuple_cached(hop, vlist) + rtype_inplace_add = rtype_add + + def convert_from_to((r_from, r_to), v, llops): + if len(r_from.items_r) == len(r_to.items_r): + if r_from.lowleveltype == r_to.lowleveltype: + return v + n = len(r_from.items_r) + items_v = [] + for i in range(n): + item_v = r_from.getitem(llops, v, i) + item_v = llops.convertvar(item_v, + r_from.items_r[i], + r_to.items_r[i]) + items_v.append(item_v) + return r_from.newtuple(llops, r_to, items_v) + return NotImplemented + Modified: pypy/dist/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rtuple.py (original) +++ pypy/dist/pypy/rpython/test/test_rtuple.py Fri Mar 24 14:50:45 2006 @@ -1,5 +1,6 @@ from pypy.translator.translator import TranslationContext from pypy.rpython.lltypesystem.lltype import * +from pypy.rpython.ootypesystem import ootype from pypy.rpython.rint import signed_repr from pypy.rpython.rbool import bool_repr from pypy.rpython.test.test_llinterp import interpret @@ -41,52 +42,102 @@ assert res.item0 == True assert res.item1 == False -def test_tuple_concatenation(): - def f(n): - tup = (1,n) - tup1 = (3,) - res = tup + tup1 + () - return res[0]*100 + res[1]*10 + res[2] - res = interpret(f, [2]) - assert res == 123 - -def test_tuple_concatenation_mix(): - def f(n): - tup = (1,n) - tup1 = ('3',) - res = tup + tup1 - return res[0]*100 + res[1]*10 + ord(res[2]) - ord('0') - res = interpret(f, [2]) - assert res == 123 - -def test_constant_tuple_contains(): - def f(i): - t1 = (1, 2, 3, 4) - return i in t1 - res = interpret(f, [3], view=False, viewbefore=False) - assert res is True - res = interpret(f, [0]) - assert res is False - -def test_constant_tuple_contains2(): - def t1(): - return (1,2,3,4) - def f(i): - return i in t1() - res = interpret(f, [3], view=False, viewbefore=False) - assert res is True - res = interpret(f, [0]) - assert res is False - - -def test_constant_unichar_tuple_contains(): - def f(i): - return unichr(i) in (u'1', u'9') - res = interpret(f, [49]) - assert res is True - res = interpret(f, [50]) - assert res is False - + def test_tuple_concatenation(self): + def f(n): + tup = (1,n) + tup1 = (3,) + res = tup + tup1 + () + return res[0]*100 + res[1]*10 + res[2] + res = self.interpret(f, [2]) + assert res == 123 + + def test_tuple_concatenation_mix(self): + def f(n): + tup = (1,n) + tup1 = ('3',) + res = tup + tup1 + return res[0]*100 + res[1]*10 + ord(res[2]) - ord('0') + res = self.interpret(f, [2]) + assert res == 123 + + def test_constant_tuple_contains(self): + def f(i): + t1 = (1, 2, 3, 4) + return i in t1 + res = self.interpret(f, [3]) + assert res is True + res = self.interpret(f, [0]) + assert res is False + + def test_constant_tuple_contains2(self): + def t1(): + return (1,2,3,4) + def f(i): + return i in t1() + res = self.interpret(f, [3]) + assert res is True + res = self.interpret(f, [0]) + assert res is False + + def test_constant_unichar_tuple_contains(self): + def f(i): + return unichr(i) in (u'1', u'9') + res = self.interpret(f, [49]) + assert res is True + res = self.interpret(f, [50]) + assert res is False + + def test_conv(self): + def t0(): + return (3, 2, None) + def t1(): + return (7, 2, "xy") + def f(i): + if i == 1: + return t1() + else: + return t0() + + res = self.interpret(f, [1]) + assert res.item0 == 7 + # XXX this assertion will fail once ootypesystem properly supports + # strings, we're leaving the fix up to that point + assert isinstance(typeOf(res.item2), Ptr) and ''.join(res.item2.chars) == "xy" + res = self.interpret(f, [0]) + assert res.item0 == 3 + # XXX see above + assert isinstance(typeOf(res.item2), Ptr) and not res.item2 + + def test_constant_tuples_shared(self): + def g(n): + x = (n, 42) # constant (5, 42) detected by the annotator + y = (5, 42) # another one, built by the flow space + z = x + () # yet another + return id(x) == id(y) == id(z) + def f(): + return g(5) + res = self.interpret(f, []) + assert res is True + + def test_inst_tuple_getitem(self): + class A: + pass + class B(A): + pass + + def f(i): + if i: + x = (1, A()) + else: + x = (1, B()) + return x[1] + + res = self.interpret(f, [0]) + if self.type_system == "lltype": + assert ''.join(res.super.typeptr.name) == "B\00" + else: + assert ootype.dynamicType(res)._name.split(".")[-1] == "B" + def test_tuple_iterator_length1(): def f(i): total = 0 @@ -96,51 +147,6 @@ res = interpret(f, [93813]) assert res == 93813 -def test_conv(): - def t0(): - return (3, 2, None) - def t1(): - return (7, 2, "xy") - def f(i): - if i == 1: - return t1() - else: - return t0() - - res = interpret(f, [1]) - assert res.item0 == 7 - assert isinstance(typeOf(res.item2), Ptr) and ''.join(res.item2.chars) == "xy" - res = interpret(f, [0]) - assert res.item0 == 3 - assert isinstance(typeOf(res.item2), Ptr) and not res.item2 - -def test_constant_tuples_shared(): - def g(n): - x = (n, 42) # constant (5, 42) detected by the annotator - y = (5, 42) # another one, built by the flow space - z = x + () # yet another - return id(x) == id(y) == id(z) - def f(): - return g(5) - res = interpret(f, []) - assert res is True - -def test_inst_tuple_getitem(): - class A: - pass - class B(A): - pass - - def f(i): - if i: - x = (1, A()) - else: - x = (1, B()) - return x[1] - - res = interpret(f, [0]) - assert ''.join(res.super.typeptr.name) == "B\00" - def test_inst_tuple_iter(): class A: pass From mwh at codespeak.net Fri Mar 24 15:00:25 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 15:00:25 +0100 (CET) Subject: [pypy-svn] r24962 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324140025.7D23510137@code0.codespeak.net> Author: mwh Date: Fri Mar 24 15:00:14 2006 New Revision: 24962 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: blah blah int_floordiv_zer. this is getting boring :) Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 15:00:14 2006 @@ -111,6 +111,7 @@ 'int_lshift': LLOp(canfold=True), 'int_rshift': LLOp(canfold=True), 'int_xor': LLOp(canfold=True), + 'int_floordiv_zer': LLOp(canfold=True, canraise=(ZeroDivisionError,)), 'int_add_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_sub_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_mul_ovf': LLOp(canfold=True, canraise=(OverflowError,)), From mwh at codespeak.net Fri Mar 24 15:00:43 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 15:00:43 +0100 (CET) Subject: [pypy-svn] r24963 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324140043.0FAA310145@code0.codespeak.net> Author: mwh Date: Fri Mar 24 15:00:42 2006 New Revision: 24963 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: an error value for UniChr Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 15:00:42 2006 @@ -16,6 +16,7 @@ lltype.UnsignedLongLong: r_ulonglong(-1), lltype.Float: -1.0, lltype.Char: chr(255), + lltype.UniChar: unichr(0xFFFF), # XXX is this always right? lltype.Bool: True, llmemory.Address: NULL, lltype.Void: None} From mwh at codespeak.net Fri Mar 24 15:04:46 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 15:04:46 +0100 (CET) Subject: [pypy-svn] r24964 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060324140446.817061013D@code0.codespeak.net> Author: mwh Date: Fri Mar 24 15:04:45 2006 New Revision: 24964 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Log: given that we've gotten the gc details correct for the moment, use the RefcountingGcPolicy in test_exceptiontransform to avoid those annoying 'too many root sets' errors. Modified: pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_exceptiontransform.py Fri Mar 24 15:04:45 2006 @@ -38,7 +38,7 @@ t.buildrtyper().specialize() ## etrafo = exceptiontransform.ExceptionTransformer(t) ## etrafo.transform_completely() - builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.BoehmGcPolicy) + builder = genc.CExtModuleBuilder(t, fn, gcpolicy=gc.RefcountingGcPolicy) builder.generate_source() skip_missing_compiler(builder.compile) builder.import_module() From mwh at codespeak.net Fri Mar 24 15:06:33 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Mar 2006 15:06:33 +0100 (CET) Subject: [pypy-svn] r24965 - pypy/branch/explicit-exceptions/translator/c/test Message-ID: <20060324140633.07EB61013D@code0.codespeak.net> Author: mwh Date: Fri Mar 24 15:06:22 2006 New Revision: 24965 Modified: pypy/branch/explicit-exceptions/translator/c/test/test_genc.py Log: delete a couple of tests testing SpaceOperation.cleanup. the status on the branch is: the framework gc is broken. the tests that don't have an rtyper are broken. there is a mystery failure in test_backendoptimized. everything else seems to work, but haven't tried a translation yet. Modified: pypy/branch/explicit-exceptions/translator/c/test/test_genc.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/test/test_genc.py (original) +++ pypy/branch/explicit-exceptions/translator/c/test/test_genc.py Fri Mar 24 15:06:22 2006 @@ -298,91 +298,3 @@ f1 = compile(f, []) assert f1() == 1 - -# ____________________________________________________________ -# test for the 'cleanup' attribute of SpaceOperations -class CleanupState(object): - pass -cleanup_state = CleanupState() -cleanup_state.current = 1 -def cleanup_g(n): - cleanup_state.saved = cleanup_state.current - try: - return 10 // n - except ZeroDivisionError: - raise -def cleanup_h(): - cleanup_state.current += 1 -def cleanup_f(n): - cleanup_g(n) - cleanup_h() # the test hacks the graph to put this h() in the - # cleanup clause of the previous direct_call(g) - return cleanup_state.saved * 100 + cleanup_state.current - -def test_cleanup_finally(): - class DummyGCTransformer(NoneGcPolicy.transformerclass): - def transform_graph(self, graph): - super(DummyGCTransformer, self).transform_graph(graph) - if graph is self.translator.graphs[0]: - operations = graph.startblock.operations - op_call_g = operations[0] - op_call_h = operations.pop(1) - assert op_call_g.opname == "direct_call" - assert op_call_h.opname == "direct_call" - assert op_call_g.cleanup == ((), ()) - assert op_call_h.cleanup == ((), ()) - cleanup_finally = (op_call_h,) - cleanup_except = () - op_call_g.cleanup = cleanup_finally, cleanup_except - op_call_h.cleanup = None - - class DummyGcPolicy(NoneGcPolicy): - transformerclass = DummyGCTransformer - - f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) - # state.current == 1 - res = f1(1) - assert res == 102 - # state.current == 2 - res = f1(1) - assert res == 203 - # state.current == 3 - py.test.raises(ZeroDivisionError, f1, 0) - # state.current == 4 - res = f1(1) - assert res == 405 - # state.current == 5 - -def test_cleanup_except(): - class DummyGCTransformer(NoneGcPolicy.transformerclass): - def transform_graph(self, graph): - super(DummyGCTransformer, self).transform_graph(graph) - if graph is self.translator.graphs[0]: - operations = graph.startblock.operations - op_call_g = operations[0] - op_call_h = operations.pop(1) - assert op_call_g.opname == "direct_call" - assert op_call_h.opname == "direct_call" - assert op_call_g.cleanup == ((), ()) - assert op_call_h.cleanup == ((), ()) - cleanup_finally = () - cleanup_except = (op_call_h,) - op_call_g.cleanup = cleanup_finally, cleanup_except - op_call_h.cleanup = None - - class DummyGcPolicy(NoneGcPolicy): - transformerclass = DummyGCTransformer - - f1 = compile(cleanup_f, [int], backendopt=False, gcpolicy=DummyGcPolicy) - # state.current == 1 - res = f1(1) - assert res == 101 - # state.current == 1 - res = f1(1) - assert res == 101 - # state.current == 1 - py.test.raises(ZeroDivisionError, f1, 0) - # state.current == 2 - res = f1(1) - assert res == 202 - # state.current == 2 From nik at codespeak.net Fri Mar 24 16:01:51 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Fri, 24 Mar 2006 16:01:51 +0100 (CET) Subject: [pypy-svn] r24967 - in pypy/dist/pypy/rpython: . lltypesystem test Message-ID: <20060324150151.CB37610137@code0.codespeak.net> Author: nik Date: Fri Mar 24 16:01:50 2006 New Revision: 24967 Modified: pypy/dist/pypy/rpython/lltypesystem/rtuple.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: support hashing, make more tuple tests pass on ootypesystem. add a test about tuple -> list conversion (skipped for ootypes for now). only iterators now left for full tuple support in ootypes. Modified: pypy/dist/pypy/rpython/lltypesystem/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rtuple.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rtuple.py Fri Mar 24 16:01:50 2006 @@ -23,61 +23,6 @@ # ... # } -_gen_eq_function_cache = {} -_gen_hash_function_cache = {} - -def gen_eq_function(items_r): - eq_funcs = [r_item.get_ll_eq_function() or operator.eq for r_item in items_r] - key = tuple(eq_funcs) - try: - return _gen_eq_function_cache[key] - except KeyError: - miniglobals = {} - source = """ -def ll_eq(t1, t2): - %s - return True -""" - body = [] - for i, eq_func in enumerate(eq_funcs): - miniglobals['eq%d' % i] = eq_func - body.append("if not eq%d(t1.item%d, t2.item%d): return False" % (i, i, i)) - body = ('\n'+' '*4).join(body) - source = source % body - exec source in miniglobals - ll_eq = miniglobals['ll_eq'] - _gen_eq_function_cache[key] = ll_eq - return ll_eq - -def gen_hash_function(items_r): - # based on CPython - hash_funcs = [r_item.get_ll_hash_function() for r_item in items_r] - key = tuple(hash_funcs) - try: - return _gen_hash_function_cache[key] - except KeyError: - miniglobals = {} - source = """ -def ll_hash(t): - retval = 0x345678 - %s - return retval -""" - body = [] - mult = 1000003 - for i, hash_func in enumerate(hash_funcs): - miniglobals['hash%d' % i] = hash_func - body.append("retval = (retval ^ hash%d(t.item%d)) * %d" % - (i, i, mult)) - mult = intmask(mult + 82520 + 2*len(items_r)) - body = ('\n'+' '*4).join(body) - source = source % body - exec source in miniglobals - ll_hash = miniglobals['ll_hash'] - _gen_hash_function_cache[key] = ll_hash - return ll_hash - - class TupleRepr(AbstractTupleRepr): def __init__(self, rtyper, items_r): @@ -100,15 +45,6 @@ def instantiate(self): return malloc(self.lowleveltype.TO) - #def get_eqfunc(self): - # return inputconst(Void, self.item_repr.get_ll_eq_function()) - - def get_ll_eq_function(self): - return gen_eq_function(self.items_r) - - def get_ll_hash_function(self): - return gen_hash_function(self.items_r) - def rtype_bltn_list(self, hop): from pypy.rpython import rlist nitems = len(self.items_r) Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Fri Mar 24 16:01:50 2006 @@ -20,6 +20,62 @@ keys = [rtyper.makekey(s_item) for s_item in self.items] return tuple([self.__class__]+keys) + +_gen_eq_function_cache = {} +_gen_hash_function_cache = {} + +def gen_eq_function(items_r): + eq_funcs = [r_item.get_ll_eq_function() or operator.eq for r_item in items_r] + key = tuple(eq_funcs) + try: + return _gen_eq_function_cache[key] + except KeyError: + miniglobals = {} + source = """ +def ll_eq(t1, t2): + %s + return True +""" + body = [] + for i, eq_func in enumerate(eq_funcs): + miniglobals['eq%d' % i] = eq_func + body.append("if not eq%d(t1.item%d, t2.item%d): return False" % (i, i, i)) + body = ('\n'+' '*4).join(body) + source = source % body + exec source in miniglobals + ll_eq = miniglobals['ll_eq'] + _gen_eq_function_cache[key] = ll_eq + return ll_eq + +def gen_hash_function(items_r): + # based on CPython + hash_funcs = [r_item.get_ll_hash_function() for r_item in items_r] + key = tuple(hash_funcs) + try: + return _gen_hash_function_cache[key] + except KeyError: + miniglobals = {} + source = """ +def ll_hash(t): + retval = 0x345678 + %s + return retval +""" + body = [] + mult = 1000003 + for i, hash_func in enumerate(hash_funcs): + miniglobals['hash%d' % i] = hash_func + body.append("retval = (retval ^ hash%d(t.item%d)) * %d" % + (i, i, mult)) + mult = intmask(mult + 82520 + 2*len(items_r)) + body = ('\n'+' '*4).join(body) + source = source % body + exec source in miniglobals + ll_hash = miniglobals['ll_hash'] + _gen_hash_function_cache[key] = ll_hash + return ll_hash + + class AbstractTupleRepr(Repr): def __init__(self, rtyper, items_r): @@ -66,6 +122,12 @@ def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) + def get_ll_eq_function(self): + return gen_eq_function(self.items_r) + + def get_ll_hash_function(self): + return gen_hash_function(self.items_r) + class __extend__(pairtype(AbstractTupleRepr, IntegerRepr)): Modified: pypy/dist/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rtuple.py (original) +++ pypy/dist/pypy/rpython/test/test_rtuple.py Fri Mar 24 16:01:50 2006 @@ -133,11 +133,70 @@ return x[1] res = self.interpret(f, [0]) - if self.type_system == "lltype": - assert ''.join(res.super.typeptr.name) == "B\00" - else: - assert ootype.dynamicType(res)._name.split(".")[-1] == "B" + assert self.class_name(res) == "B" + + def test_inst_tuple_add_getitem(self): + class A: + pass + class B(A): + pass + + def f(i): + x = (1, A()) + y = (2, B()) + if i: + z = x + y + else: + z = y + x + return z[1] + + res = self.interpret(f, [1]) + assert self.class_name(res) == "A" + + res = self.interpret(f, [0]) + assert self.class_name(res) == "B" + + def test_type_erase(self): + class A(object): + pass + class B(object): + pass + + def f(): + return (A(), B()), (B(), A()) + + t = TranslationContext() + s = t.buildannotator().build_types(f, []) + rtyper = t.buildrtyper(type_system=self.type_system) + rtyper.specialize() + + s_AB_tup = s.items[0] + s_BA_tup = s.items[1] + + r_AB_tup = rtyper.getrepr(s_AB_tup) + r_BA_tup = rtyper.getrepr(s_AB_tup) + + assert r_AB_tup.lowleveltype == r_BA_tup.lowleveltype + + def test_tuple_hash(self): + def f(i, j): + return hash((i, j)) + + res1 = self.interpret(f, [12, 27]) + res2 = self.interpret(f, [27, 12]) + assert res1 != res2 + + def test_tuple_to_list(self): + if self.type_system == "ootype": + py.test.skip("XXX fix me if ootypes support lists") + def f(i, j): + return list((i, j)) + + res = self.interpret(f, [2, 3]) + assert res._obj.items == [2, 3] + + def test_tuple_iterator_length1(): def f(i): total = 0 @@ -166,66 +225,18 @@ res = interpret(f, [0]) assert ''.join(res.super.typeptr.name) == "B\00" - -def test_inst_tuple_add_getitem(): - class A: - pass - class B(A): - pass - - def f(i): - x = (1, A()) - y = (2, B()) - if i: - z = x + y - else: - z = y + x - return z[1] - - res = interpret(f, [1]) - assert ''.join(res.super.typeptr.name) == "A\00" - - res = interpret(f, [0]) - assert ''.join(res.super.typeptr.name) == "B\00" - - -def test_type_erase(): - class A(object): - pass - class B(object): - pass - - def f(): - return (A(), B()), (B(), A()) - - t = TranslationContext() - s = t.buildannotator().build_types(f, []) - rtyper = t.buildrtyper() - rtyper.specialize() - - s_AB_tup = s.items[0] - s_BA_tup = s.items[1] - - r_AB_tup = rtyper.getrepr(s_AB_tup) - r_BA_tup = rtyper.getrepr(s_AB_tup) - - assert r_AB_tup.lowleveltype == r_BA_tup.lowleveltype - - -def test_tuple_hash(): - def f(i, j): - return hash((i, j)) - - res1 = interpret(f, [12, 27]) - res2 = interpret(f, [27, 12]) - assert res1 != res2 - class TestLLTuple(AbstractTestRTuple): type_system = "lltype" + def class_name(self, value): + return "".join(value.super.typeptr.name)[:-1] + class TestOOTuple(AbstractTestRTuple): type_system = "ootype" + def class_name(self, value): + return ootype.dynamicType(value)._name.split(".")[-1] + From cfbolz at codespeak.net Fri Mar 24 16:04:19 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 24 Mar 2006 16:04:19 +0100 (CET) Subject: [pypy-svn] r24968 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324150419.4B92A10141@code0.codespeak.net> Author: cfbolz Date: Fri Mar 24 16:04:18 2006 New Revision: 24968 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: remove excessive print statement Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 16:04:18 2006 @@ -143,7 +143,6 @@ lastblock = block for i in range(last_operation, -1, -1): op = block.operations[i] - print "considering op", op, i if not self.raise_analyzer.can_raise(op): continue From arigo at codespeak.net Fri Mar 24 16:38:46 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Mar 2006 16:38:46 +0100 (CET) Subject: [pypy-svn] r24969 - in pypy/dist/pypy/jit: . test Message-ID: <20060324153846.4ECFC10150@code0.codespeak.net> Author: arigo Date: Fri Mar 24 16:38:38 2006 New Revision: 24969 Modified: pypy/dist/pypy/jit/hintannotator.py pypy/dist/pypy/jit/hintmodel.py pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: A (disabled) test about the next possible thing to do: virtual containers in red variables. Modified: pypy/dist/pypy/jit/hintannotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator.py (original) +++ pypy/dist/pypy/jit/hintannotator.py Fri Mar 24 16:38:38 2006 @@ -1,6 +1,7 @@ from pypy.annotation.annrpython import RPythonAnnotator, _registeroperations from pypy.jit import hintmodel from pypy.jit.hintbookkeeper import HintBookkeeper +from pypy.rpython.lltypesystem import lltype class HintAnnotator(RPythonAnnotator): @@ -20,13 +21,19 @@ def consider_op_malloc(self, hs_TYPE): TYPE = hs_TYPE.const - vstructdef = self.bookkeeper.getvirtualcontainerdef(TYPE) - return hintmodel.SomeLLAbstractContainer(vstructdef) + if getattr(self.policy, 'novirtualcontainer', False): + return hintmodel.SomeLLAbstractVariable(lltype.Ptr(TYPE)) + else: + vstructdef = self.bookkeeper.getvirtualcontainerdef(TYPE) + return hintmodel.SomeLLAbstractContainer(vstructdef) def consider_op_malloc_varsize(self, hs_TYPE, hs_length): TYPE = hs_TYPE.const - vcontainerdef = self.bookkeeper.getvirtualcontainerdef(TYPE) - return hintmodel.SomeLLAbstractContainer(vcontainerdef) + if getattr(self.policy, 'novirtualcontainer', False): + return hintmodel.SomeLLAbstractVariable(lltype.Ptr(TYPE)) + else: + vcontainerdef = self.bookkeeper.getvirtualcontainerdef(TYPE) + return hintmodel.SomeLLAbstractContainer(vcontainerdef) def consider_op_keepalive(self, hs_v): pass Modified: pypy/dist/pypy/jit/hintmodel.py ============================================================================== --- pypy/dist/pypy/jit/hintmodel.py (original) +++ pypy/dist/pypy/jit/hintmodel.py Fri Mar 24 16:38:38 2006 @@ -90,9 +90,9 @@ for the pygame viewer """ if self.eager_concrete: - return (0,100,0) + return (0,100,0) # green elif self.is_fixed(): - return (50,140,0) + return (50,140,0) # green-dark-cyan else: return None annotationcolor = property(annotationcolor) @@ -101,7 +101,7 @@ pass class SomeLLAbstractContainer(SomeLLAbstractValue): - annotationcolor = (0,60,160) + annotationcolor = (0,60,160) # blue def __init__(self, contentdef): self.contentdef = contentdef Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Fri Mar 24 16:38:38 2006 @@ -256,6 +256,14 @@ else: return hs_c.__class__, "red", hs_c.concretetype +class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractVariable)): + + def rtyper_makerepr((ts, hs_v), hrtyper): + return hrtyper.getredrepr(hs_v.concretetype) + + def rtyper_makekey((ts, hs_v), hrtyper): + return hs_v.__class__, "red", hs_v.concretetype + class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractContainer)): def rtyper_makerepr((ts, hs_container), hrtyper): Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Fri Mar 24 16:38:38 2006 @@ -12,9 +12,12 @@ from pypy.annotation import model as annmodel from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph +from pypy.annotation.policy import AnnotatorPolicy from pypy.translator.backendopt.inline import auto_inlining from pypy import conftest +P_NOVIRTUAL = AnnotatorPolicy() +P_NOVIRTUAL.novirtualcontainer = True def hannotate(func, values, policy=None, inline=None): # build the normal ll graphs for ll_function @@ -37,8 +40,9 @@ hannotator.translator.view() return hs, hannotator, rtyper -def timeshift(ll_function, values, opt_consts=[], inline=None): - hs, ha, rtyper = hannotate(ll_function, values, inline=inline) +def timeshift(ll_function, values, opt_consts=[], inline=None, policy=None): + hs, ha, rtyper = hannotate(ll_function, values, + inline=inline, policy=policy) htshift = HintTimeshift(ha, rtyper) htshift.timeshift() t = rtyper.annotator.translator @@ -354,3 +358,17 @@ insns, res = timeshift(ll_plus_minus, [s, 0, 2], [0], inline=999) assert res == ll_plus_minus("+-+", 0, 2) assert insns == {'int_add': 2, 'int_sub': 1} + +def test_red_virtual_container(): + # this checks that red boxes are able to be virtualized dynamically by + # the compiler (the P_NOVIRTUAL policy prevents the hint-annotator from + # marking variables in blue) + py.test.skip("in-progress") + S = lltype.GcStruct('S', ('n', lltype.Signed)) + def ll_function(n): + s = lltype.malloc(S) + s.n = n + return s.n + insns, res = timeshift(ll_function, [42], [], policy=P_NOVIRTUAL) + assert res == 42 + assert insns == {} From cfbolz at codespeak.net Fri Mar 24 16:48:38 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 24 Mar 2006 16:48:38 +0100 (CET) Subject: [pypy-svn] r24970 - pypy/branch/explicit-exceptions/translator/c Message-ID: <20060324154838.5D4C810156@code0.codespeak.net> Author: cfbolz Date: Fri Mar 24 16:48:32 2006 New Revision: 24970 Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Log: some cosmetics Modified: pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py (original) +++ pypy/branch/explicit-exceptions/translator/c/exceptiontransform.py Fri Mar 24 16:48:32 2006 @@ -5,6 +5,7 @@ c_last_exception, SpaceOperation, checkgraph, FunctionGraph from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.memory.lladdress import NULL +from pypy.rpython.memory.gctransform import varoftype from pypy.rpython import rclass from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong from pypy.annotation import model as annmodel @@ -32,7 +33,9 @@ def __init__(self, translator): self.translator = translator self.raise_analyzer = canraise.RaiseAnalyzer(translator) - self.exc_data = translator.rtyper.getexceptiondata() + edata = translator.rtyper.getexceptiondata() + self.lltype_of_exception_value = edata.lltype_of_exception_value + self.lltype_of_exception_type = edata.lltype_of_exception_type mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) l2a = annmodel.lltype_to_annotation @@ -42,8 +45,8 @@ #exc_value = lltype.nullptr(self.exc_data.lltype_of_exception_value.TO) exc_data = ExcData() - null_type = lltype.nullptr(self.exc_data.lltype_of_exception_type.TO) - null_value = lltype.nullptr(self.exc_data.lltype_of_exception_value.TO) + null_type = lltype.nullptr(self.lltype_of_exception_type.TO) + null_value = lltype.nullptr(self.lltype_of_exception_value.TO) def rpyexc_occured(): return exc_data.exc_type is not null_type @@ -71,19 +74,19 @@ graph=rpyexc_occured_graph), lltype.Ptr(RPYEXC_OCCURED_TYPE)) - RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_type) + RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.lltype_of_exception_type) rpyexc_fetch_type_graph = mixlevelannotator.getgraph( rpyexc_fetch_type, [], - l2a(self.exc_data.lltype_of_exception_type)) + l2a(self.lltype_of_exception_type)) self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", graph=rpyexc_fetch_type_graph), lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE)) - RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.exc_data.lltype_of_exception_value) + RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.lltype_of_exception_value) rpyexc_fetch_value_graph = mixlevelannotator.getgraph( rpyexc_fetch_value, [], - l2a(self.exc_data.lltype_of_exception_value)) + l2a(self.lltype_of_exception_value)) self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", graph=rpyexc_fetch_value_graph), @@ -97,12 +100,12 @@ graph=rpyexc_clear_graph), lltype.Ptr(RPYEXC_CLEAR)) - RPYEXC_RAISE = lltype.FuncType([self.exc_data.lltype_of_exception_type, - self.exc_data.lltype_of_exception_value], + RPYEXC_RAISE = lltype.FuncType([self.lltype_of_exception_type, + self.lltype_of_exception_value], lltype.Void) rpyexc_raise_graph = mixlevelannotator.getgraph( - rpyexc_raise, [l2a(self.exc_data.lltype_of_exception_type), - l2a(self.exc_data.lltype_of_exception_value)], + rpyexc_raise, [l2a(self.lltype_of_exception_type), + l2a(self.lltype_of_exception_value)], l2a(lltype.Void)) self.rpyexc_raise_ptr = Constant(lltype.functionptr( RPYEXC_RAISE, "RPyRaiseException", @@ -211,36 +214,29 @@ startblock = Block(inputargs) startblock.operations.append(newop) newgraph = FunctionGraph("dummy_exc1", startblock) - # XXX this is makes stackless happier, for very bad reasons. - # XXX do something about this. - newgraph.func = None startblock.closeblock(Link([result], newgraph.returnblock)) startblock.exits = list(startblock.exits) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype self.gen_exc_check(startblock, newgraph.returnblock) startblock.exits[0].exitcase = startblock.exits[0].llexitcase = False excblock = Block([]) - var_value = Variable() - var_value.concretetype = self.exc_data.lltype_of_exception_value - var_type = Variable() - var_type.concretetype = self.exc_data.lltype_of_exception_type - var_void = Variable() - var_void.concretetype = lltype.Void + var_value = varoftype(self.lltype_of_exception_value) + var_type = varoftype(self.lltype_of_exception_type) + var_void = varoftype(lltype.Void) excblock.operations.append(SpaceOperation( "direct_call", [self.rpyexc_fetch_value_ptr], var_value)) excblock.operations.append(SpaceOperation( "direct_call", [self.rpyexc_fetch_type_ptr], var_type)) excblock.operations.append(SpaceOperation( "direct_call", [self.rpyexc_clear_ptr], var_void)) - newgraph.exceptblock.inputargs[0].concretetype = self.exc_data.lltype_of_exception_type - newgraph.exceptblock.inputargs[1].concretetype = self.exc_data.lltype_of_exception_value + newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type + newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) startblock.exits[True].target = excblock startblock.exits[True].args = [] FUNCTYPE = lltype.FuncType(ARGTYPES, op.result.concretetype) fptr = Constant(lltype.functionptr(FUNCTYPE, "dummy_exc2", graph=newgraph), lltype.Ptr(FUNCTYPE)) - self.translator.graphs.append(newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) def gen_exc_check(self, block, returnblock): From pedronis at codespeak.net Fri Mar 24 17:33:21 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 24 Mar 2006 17:33:21 +0100 (CET) Subject: [pypy-svn] r24971 - in pypy/dist/pypy: annotation interpreter interpreter/test Message-ID: <20060324163321.8769310153@code0.codespeak.net> Author: pedronis Date: Fri Mar 24 17:33:14 2006 New Revision: 24971 Added: pypy/dist/pypy/interpreter/test/test_argument.py (contents, props changed) Modified: pypy/dist/pypy/annotation/annrpython.py pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/annotation/description.py pypy/dist/pypy/interpreter/argument.py Log: (arre, pedronis) the logic in FunctionDesc.pycall may have discared changes to inputcells done by specialisation when reparsing the args object. Reconstruct a new args object out of the possibly changed inputcells instead. Introduced an unmatch_signature helper for this with some tests. Modified: pypy/dist/pypy/annotation/annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/annrpython.py (original) +++ pypy/dist/pypy/annotation/annrpython.py Fri Mar 24 17:33:14 2006 @@ -95,6 +95,7 @@ return self.build_graph_types(flowgraph, inputcells) def annotate_helper(self, function, args_s, policy=None, complete_now=True): + args_s = args_s[:] saved = self.policy, self.added_blocks if policy is None: from pypy.annotation.policy import AnnotatorPolicy Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Fri Mar 24 17:33:14 2006 @@ -673,7 +673,10 @@ def type(self, item): return type(item) - + + def is_true(self, s_tup): + assert isinstance(s_tup, SomeTuple) + return bool(s_tup.items) class CallPatternTooComplex(Exception): pass Modified: pypy/dist/pypy/annotation/description.py ============================================================================== --- pypy/dist/pypy/annotation/description.py (original) +++ pypy/dist/pypy/annotation/description.py Fri Mar 24 17:33:14 2006 @@ -222,8 +222,10 @@ if isinstance(result, FunctionGraph): graph = result # common case # if that graph has a different signature, we need to re-parse - # the arguments - inputcells = self.parse_arguments(args, graph) + # the arguments. + # recreate the args object because inputcells may have been changed + new_args = args.unmatch_signature(self.signature, inputcells) + inputcells = self.parse_arguments(new_args, graph) result = schedule(graph, inputcells) # Some specializations may break the invariant of returning # annotations that are always more general than the previous time. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Fri Mar 24 17:33:14 2006 @@ -82,6 +82,49 @@ self._match_signature(scope_w, argnames, has_vararg, has_kwarg, defaults_w, 0, None) return scope_w + def unmatch_signature(self, signature, data_w): + """kind of inverse of match_signature""" + args_w, kwds_w = self.unpack() + need_cnt = len(args_w) + need_kwds = kwds_w.keys() + space = self.space + argnames, varargname, kwargname = signature + cnt = len(argnames) + data_args_w = data_w[:cnt] + if varargname: + data_w_stararg = data_w[cnt] + cnt += 1 + else: + data_w_stararg = space.newtuple([]) + + unfiltered_kwds_w = {} + if kwargname: + data_w_starargarg = data_w[cnt] + for w_key in space.unpackiterable(data_w_starargarg): + key = space.str_w(w_key) + w_value = space.getitem(data_w_starargarg, w_key) + unfiltered_kwds_w[key] = w_value + cnt += 1 + assert len(data_w) == cnt + + ndata_args_w = len(data_args_w) + if ndata_args_w >= need_cnt: + args_w = data_args_w[:need_cnt] + for argname, w_arg in zip(argnames[need_cnt:], data_args_w[need_cnt:]): + unfiltered_kwds_w[argname] = w_arg + assert not space.is_true(data_w_stararg) + else: + args_w = data_args_w[:] + for w_stararg in space.unpackiterable(data_w_stararg): + args_w.append(w_stararg) + assert len(args_w) == need_cnt + + kwds_w = {} + for key in need_kwds: + kwds_w[key] = unfiltered_kwds_w[key] + + return Arguments(self.space, args_w, kwds_w) + def normalize(self): """Return an instance of the Arguments class. (Instances of other classes may not be suitable for long-term storage or multiple Added: pypy/dist/pypy/interpreter/test/test_argument.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/interpreter/test/test_argument.py Fri Mar 24 17:33:14 2006 @@ -0,0 +1,92 @@ +from pypy.interpreter.argument import Arguments + + +class DummySpace(object): + def newtuple(self, items): + return tuple(items) + + def is_true(self, obj): + return bool(obj) + + def unpackiterable(self, it): + return list(it) + + def newdict(self, items): + return dict(items) + + def setitem(self, obj, key, value): + obj[key] = value + + def getitem(self, obj, key): + return obj[key] + + def wrap(self, obj): + return obj + + def str_w(self, s): + return str(s) + + def isinstance(self, obj, cls): + return isinstance(obj, cls) + + w_dict = dict + +class TestArguments(object): + + + def test_unmatch_signature(self): + space = DummySpace() + args = Arguments(space, [1,2,3]) + sig = (['a', 'b', 'c'], None, None) + data = args.match_signature(sig, []) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1]) + sig = (['a', 'b', 'c'], None, None) + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1,2,3,4,5]) + sig = (['a', 'b', 'c'], 'r', None) + data = args.match_signature(sig, []) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1], {'c': 3, 'b': 2}) + sig = (['a', 'b', 'c'], None, None) + data = args.match_signature(sig, []) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1], {'c': 5}) + sig = (['a', 'b', 'c'], None, None) + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1], {'c': 5, 'd': 7}) + sig = (['a', 'b', 'c'], None, 'kw') + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1,2,3,4,5], {'e': 5, 'd': 7}) + sig = (['a', 'b', 'c'], 'r', 'kw') + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [], {}, w_stararg=[1], w_starstararg={'c': 5, 'd': 7}) + sig = (['a', 'b', 'c'], None, 'kw') + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + + args = Arguments(space, [1,2], {'g': 9}, w_stararg=[3,4,5], w_starstararg={'e': 5, 'd': 7}) + sig = (['a', 'b', 'c'], 'r', 'kw') + data = args.match_signature(sig, [2, 3]) + new_args = args.unmatch_signature(sig, data) + assert args.unpack() == new_args.unpack() + From cfbolz at codespeak.net Fri Mar 24 17:34:57 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 24 Mar 2006 17:34:57 +0100 (CET) Subject: [pypy-svn] r24972 - pypy/branch/explicit-exceptions/rpython/lltypesystem Message-ID: <20060324163457.9E85B10155@code0.codespeak.net> Author: cfbolz Date: Fri Mar 24 17:34:56 2006 New Revision: 24972 Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Log: we sure have many interesting operations Modified: pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/explicit-exceptions/rpython/lltypesystem/lloperation.py Fri Mar 24 17:34:56 2006 @@ -203,6 +203,11 @@ 'llong_ne': LLOp(canfold=True), 'llong_gt': LLOp(canfold=True), 'llong_ge': LLOp(canfold=True), + 'llong_and': LLOp(canfold=True), + 'llong_or': LLOp(canfold=True), + 'llong_lshift': LLOp(canfold=True), + 'llong_rshift': LLOp(canfold=True), + 'llong_xor': LLOp(canfold=True), 'ullong_is_true': LLOp(canfold=True), 'ullong_neg': LLOp(canfold=True), @@ -222,6 +227,11 @@ 'ullong_ne': LLOp(canfold=True), 'ullong_gt': LLOp(canfold=True), 'ullong_ge': LLOp(canfold=True), + 'ulong_and': LLOp(canfold=True), + 'ulong_or': LLOp(canfold=True), + 'ulong_lshift': LLOp(canfold=True), + 'ulong_rshift': LLOp(canfold=True), + 'ulong_xor': LLOp(canfold=True), 'cast_bool_to_int': LLOp(canfold=True), 'cast_bool_to_uint': LLOp(canfold=True), From antocuni at codespeak.net Fri Mar 24 18:19:14 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 24 Mar 2006 18:19:14 +0100 (CET) Subject: [pypy-svn] r24973 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060324171914.BF88E10158@code0.codespeak.net> Author: antocuni Date: Fri Mar 24 18:18:54 2006 New Revision: 24973 Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/compile.py pypy/dist/pypy/translator/cli/test/runtest.py pypy/dist/pypy/translator/cli/test/test_op.py Log: Addedd support to float, unsigned, and long types. Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Fri Mar 24 18:18:54 2006 @@ -2,7 +2,8 @@ Translate between PyPy ootypesystem and .NET Common Type System """ -from pypy.rpython.lltypesystem.lltype import Signed, Void, Bool +from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float +from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong from pypy.translator.cli import conftest from pypy.tool.ansi_print import ansi_log @@ -12,14 +13,22 @@ _lltype_to_cts = { - Signed: 'int32', Void: 'void', + Signed: 'int32', + Unsigned: 'unsigned int32', + SignedLongLong: 'int64', + UnsignedLongLong: 'unsigned int64', Bool: 'bool', + Float: 'float64', } _cts_to_ilasm = { 'int32': 'i4', - 'bool': 'i4' + 'unsigned int32': 'i4', + 'int64': 'i8', + 'unsigned int64': 'i8', + 'bool': 'i4', + 'float64': 'r8', } def lltype_to_cts(t): @@ -33,15 +42,19 @@ assert False, 'Unknown type %s' % t def lltype_to_ilasm(t): + return ctstype_to_ilasm(lltype_to_cts(t)) + +def ctstype_to_ilasm(t): try: - return _cts_to_ilasm[lltype_to_cts(t)] + return _cts_to_ilasm[t] except KeyError: if conftest.option.nostop: log.WARNING('Unknown ilasm type %s' % t) return t else: assert False, 'Unknown ilasm type %s' % t - + + def llvar_to_cts(var): return lltype_to_cts(var.concretetype), var.name @@ -49,11 +62,16 @@ return lltype_to_cts(const.concretetype), const.value def llconst_to_ilasm(const): + """ + Return the const as a string suitable for ilasm. + """ ilasm_type = lltype_to_ilasm(const.concretetype) if const.concretetype is Bool: - return ilasm_type, int(const.value) + return ilasm_type, str(int(const.value)) + elif const.concretetype is Float: + return ilasm_type, repr(const.value) else: - return ilasm_type, const.value + return ilasm_type, str(const.value) def graph_to_signature(graph): ret_type, ret_var = llvar_to_cts(graph.getreturnvar()) Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Fri Mar 24 18:18:54 2006 @@ -72,7 +72,8 @@ # .NET runtime that seems to need a return statement at the # end of the function if returntype != 'void': - self.ilasm.opcode('ldc.i4.0') + ilasm_type = cts.ctstype_to_ilasm(returntype) + self.ilasm.opcode('ldc.%s 0' % ilasm_type) self.ilasm.opcode('ret') Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Fri Mar 24 18:18:54 2006 @@ -10,21 +10,21 @@ opcodes = { 'same_as': DoNothing, # TODO: does same_as really do nothing else than renaming? - 'direct_call': None, # for now it's a special case - 'indirect_call': None, + 'direct_call': None, # for now it's a special case + 'indirect_call': None, # when it's generated? # __________ numeric operations __________ 'bool_not': Not, - 'char_lt': 'clt', + 'char_lt': None, 'char_le': None, - 'char_eq': 'ceq', + 'char_eq': None, 'char_ne': None, 'char_gt': None, 'char_ge': None, - 'unichar_eq': None, + 'unichar_eq': None, # should we unify unichar and char, as Jython does? 'unichar_ne': None, 'int_is_true': DoNothing, @@ -73,87 +73,87 @@ 'int_floordiv_ovf_zer': None, 'int_mod_ovf_zer': None, - 'uint_is_true': None, - 'uint_neg': None, - 'uint_abs': None, - 'uint_invert': None, - - 'uint_add': None, - 'uint_sub': None, - 'uint_mul': None, - 'uint_div': None, - 'uint_truediv': None, - 'uint_floordiv': None, - 'uint_mod': None, - 'uint_lt': None, - 'uint_le': None, - 'uint_eq': None, - 'uint_ne': None, - 'uint_gt': None, - 'uint_ge': None, - 'uint_and': None, - 'uint_or': None, - 'uint_lshift': None, - 'uint_rshift': None, - 'uint_xor': None, - - 'float_is_true': None, - 'float_neg': None, - 'float_abs': None, - - 'float_add': None, - 'float_sub': None, - 'float_mul': None, - 'float_div': None, - 'float_truediv': None, - 'float_floordiv': None, - 'float_mod': None, - 'float_lt': None, - 'float_le': None, - 'float_eq': None, - 'float_ne': None, - 'float_gt': None, - 'float_ge': None, - 'float_floor': None, - 'float_fmod': None, - - 'llong_is_true': None, - 'llong_neg': None, - 'llong_abs': None, - 'llong_invert': None, - - 'llong_add': None, - 'llong_sub': None, - 'llong_mul': None, - 'llong_div': None, - 'llong_truediv': None, - 'llong_floordiv': None, - 'llong_mod': None, - 'llong_lt': None, - 'llong_le': None, - 'llong_eq': None, - 'llong_ne': None, - 'llong_gt': None, - 'llong_ge': None, - - 'ullong_is_true': None, - 'ullong_neg': None, - 'ullong_abs': None, - 'ullong_invert': None, - - 'ullong_add': None, - 'ullong_sub': None, - 'ullong_mul': None, - 'ullong_div': None, - 'ullong_truediv': None, - 'ullong_floordiv': None, - 'ullong_mod': None, - 'ullong_lt': None, - 'ullong_le': None, - 'ullong_eq': None, - 'ullong_ne': None, - 'ullong_gt': None, - 'ullong_ge': None, + 'uint_is_true': DoNothing, + 'uint_neg': None, # What's the meaning? + 'uint_abs': None, # TODO + 'uint_invert': 'not', + + 'uint_add': 'add', + 'uint_sub': 'sub', + 'uint_mul': 'mul', + 'uint_div': 'div.un', + 'uint_truediv': None, # TODO + 'uint_floordiv': 'div.un', + 'uint_mod': 'rem.un', + 'uint_lt': 'clt.un', + 'uint_le': _not('cgt.un'), + 'uint_eq': 'ceq', + 'uint_ne': _not('ceq'), + 'uint_gt': 'cgt.un', + 'uint_ge': _not('clt.un'), + 'uint_and': 'and', + 'uint_or': 'or', + 'uint_lshift': 'shl', + 'uint_rshift': 'shr.un', + 'uint_xor': 'xor', + + 'float_is_true': [PushArgs, 'ldc.r8 0', 'ceq']+Not, + 'float_neg': 'neg', + 'float_abs': None, # TODO + + 'float_add': 'add', + 'float_sub': 'sub', + 'float_mul': 'mul', + 'float_div': 'div', + 'float_truediv': 'div', + 'float_floordiv': None, # TODO + 'float_mod': 'rem', + 'float_lt': 'clt', + 'float_le': _not('cgt'), + 'float_eq': 'ceq', + 'float_ne': _not('ceq'), + 'float_gt': 'cgt', + 'float_ge': _not('clt'), + 'float_floor': None, # TODO + 'float_fmod': None, # TODO + + 'llong_is_true': [PushArgs, 'ldc.i8 0', 'ceq']+Not, + 'llong_neg': 'neg', + 'llong_abs': None, # TODO + 'llong_invert': 'not', + + 'llong_add': 'add', + 'llong_sub': 'sub', + 'llong_mul': 'mul', + 'llong_div': 'div', + 'llong_truediv': None, # TODO + 'llong_floordiv': 'div', + 'llong_mod': 'rem', + 'llong_lt': 'clt', + 'llong_le': _not('cgt'), + 'llong_eq': 'ceq', + 'llong_ne': _not('ceq'), + 'llong_gt': 'cgt', + 'llong_ge': _not('clt'), + + 'ullong_is_true': [PushArgs, 'ldc.i8 0', 'ceq']+Not, + 'ullong_neg': None, + 'ullong_abs': None, # TODO + 'ullong_invert': 'not', + + 'ullong_add': 'add', + 'ullong_sub': 'sub', + 'ullong_mul': 'mul', + 'ullong_div': 'div.un', + 'ullong_truediv': None, # TODO + 'ullong_floordiv': 'div.un', + 'ullong_mod': 'rem.un', + 'ullong_lt': 'clt.un', + 'ullong_le': _not('cgt.un'), + 'ullong_eq': 'ceq', + 'ullong_ne': _not('ceq.un'), + 'ullong_gt': 'cgt.un', + 'ullong_ge': _not('clt.un'), 'cast_bool_to_int': None, 'cast_bool_to_uint': None, Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Fri Mar 24 18:18:54 2006 @@ -1,6 +1,8 @@ #!/bin/env python +import sys import py +from pypy.rpython.rarithmetic import r_int, r_uint, r_ulonglong, r_longlong from pypy.translator.test import snippet as s from pypy.translator.cli import conftest from pypy.translator.cli.test.runtest import compile_function @@ -22,17 +24,17 @@ print 'OK' -def bar(x, y): - if x>y: - return x - else: - return y +def bar(x, y): + return x and (not y) +f = compile_function(bar, [r_uint, r_uint]) -f = compile_function(bar, [int, int]) +try: + check(f, bar, r_uint(sys.maxint+1), r_uint(42)) + check(f, bar, 4, 5) +except py.test.Item.Skipped: + print 'Test skipped' -check(f, bar, 3, 3) -check(f, bar, 4, 5) #compile_function(s.is_perfect_number, [int]) Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Fri Mar 24 18:18:54 2006 @@ -11,9 +11,17 @@ from pypy.translator.cli.cts import graph_to_signature from pypy.translator.cli.cts import llvar_to_cts +FLOAT_PRECISION = 8 + def check(func, annotation, args): mono = compile_function(func, annotation) - assert func(*args) == mono(*args) + res1 = func(*args) + res2 = mono(*args) + + if type(res1) is float: + assert round(res1, FLOAT_PRECISION) == round(res2, FLOAT_PRECISION) + else: + assert res1 == res2 class TestEntryPoint(Node): """ @@ -36,7 +44,8 @@ ilasm.opcode('ldc.i4.%d' % i) ilasm.opcode('ldelem.ref') arg_type, arg_var = llvar_to_cts(arg) - ilasm.call('int32 class [mscorlib]System.Convert::To%s(string)' % arg_type.capitalize()) + ilasm.call('%s class [mscorlib]System.Convert::%s(string)' % + (arg_type, self.__convert_method(arg_type))) ilasm.call(graph_to_signature(self.graph)) @@ -46,6 +55,21 @@ ilasm.opcode('ret') ilasm.end_function() + def __convert_method(self, arg_type): + _conv = { + 'int32': 'ToInt32', + 'unsigned int32': 'ToUInt32', + 'int64': 'ToInt64', + 'unsigned int64': 'ToUInt64', + 'bool': 'ToBool', + 'float64': 'ToDouble' + } + + try: + return _conv[arg_type] + except KeyError: + assert False, 'Input type %s not supported' % arg_type + class compile_function: def __init__(self, func, annotation=[], graph=None): @@ -100,7 +124,7 @@ self.__check_helper("ilasm") retval = subprocess.call(["ilasm", tmpfile], stdout=subprocess.PIPE) - assert retval == 0, 'ilasm failed to assemble %s' % tmpfile + assert retval == 0, 'ilasm failed to assemble %s (%s)' % (self.graph.name, tmpfile) return tmpfile.replace('.il', '.exe') def __call__(self, *args): @@ -115,8 +139,10 @@ assert retval == 0, stderr ret_type, ret_var = llvar_to_cts(self.graph.getreturnvar()) - if ret_type == 'int32': + if 'int' in ret_type: return int(stdout) + elif ret_type == 'float64': + return float(stdout) elif ret_type == 'bool': return stdout.strip().lower() == 'true' else: Modified: pypy/dist/pypy/translator/cli/test/test_op.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_op.py (original) +++ pypy/dist/pypy/translator/cli/test/test_op.py Fri Mar 24 18:18:54 2006 @@ -1,25 +1,53 @@ from pypy.translator.cli.test.runtest import check +from pypy.rpython.rarithmetic import r_uint, r_ulonglong, r_longlong + +import sys def test_op(): for name, func in globals().iteritems(): - if name.startswith('op_'): - yield check, func, [int, int], (3, 4) + if not name.startswith('op_'): + continue + + any = '_any_' in name + if any or '_int_' in name: + yield check, func, [int, int], (42, 13) + + if any or '_uint_' in name: + yield check, func, [r_uint, r_uint], (r_uint(sys.maxint+1), r_uint(42)) + + if any or '_long_' in name: + yield check, func, [r_longlong, r_longlong], (r_longlong(sys.maxint*3), r_longlong(42)) + + if any or '_ulong_' in name: + yield check, func, [r_ulonglong, r_ulonglong], (r_ulonglong(sys.maxint*3), r_ulonglong(42)) + if any or '_float_' in name: + yield check, func, [float, float], (42.0, (10.0/3)) -def op_neg(x, y): + + +def op_int_long_float_neg(x, y): return -x -def op_less_equal(x, y): +def op_any_ge(x, y): + return x>=y + +def op_any_le(x, y): return x<=y -def op_and_not(x, y): +def op_int_float_and_not(x, y): return x and (not y) -def op_shift(x, y): +def op_int_uint_shift(x, y): return x<<3 + y>>4 -def op_bit_and_or_not_xor(x, y): +def op_int_uint_bitwise(x, y): return (x&y) | ~(x^y) -def op_operations(x, y): - return (x*y) / (x-y) +(-x) +def op_int_long_uint_ulong_modulo(x, y): + return x%y + +def op_any_operations(x, y): + return (x*y) + (x-y) + (x/y) + +print op_int_uint_bitwise(r_uint(42), r_uint(13)) From pedronis at codespeak.net Fri Mar 24 18:20:45 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 24 Mar 2006 18:20:45 +0100 (CET) Subject: [pypy-svn] r24974 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060324172045.233F61015A@code0.codespeak.net> Author: pedronis Date: Fri Mar 24 18:20:30 2006 New Revision: 24974 Modified: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt Log: (arre, pedronis) List of possible topics for Tokyo. Please comment if you have other suggestions. Modified: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt Fri Mar 24 18:20:30 2006 @@ -1,12 +1,12 @@ Tokyo PyPy Sprint: 23rd - 29th April 2006 ============================================================ -The next PyPy sprint is scheduled to take place 23rd- 29th April 2006 -(Sunday-Saturday) in Akihabara, Tokyo, Japan. We will together with -FSIJ (Free Software Initiative of Japan) aim to promote Python and PyPy. -We therefor invite Japanese hackers knowledgeable in Python to join our sprint! -We'll give newcomer-friendly introductions and the focus will -mainly be XXX. To learn more about the new Python-in-Python implementation look here: +The next PyPy sprint is scheduled to take place 23rd- 29th April 2006 +(Sunday-Saturday) in Akihabara, Tokyo, Japan. We will together with +FSIJ (Free Software Initiative of Japan) aim to promote Python and +PyPy. We therefor invite Japanese hackers knowledgeable in Python to +join our sprint! We'll give newcomer-friendly introductions. To learn +more about the new Python-in-Python implementation look here: http://codespeak.net/pypy @@ -21,13 +21,27 @@ Goals and topics of the sprint ------------------------------ -XXX +Possible suggestions for topics are: - - XXX - - XXX - - XXX - - whatever participants want to do with PyPy (please send - suggestions to the mailing list before to allow us to plan + - Work on gensqueak (our Squeak backend) or possibly other backends. + + - Implementing Python 2.5 features in PyPy. + + - Progress further on an 'rctypes' module aiming at letting us use a ctypes + implementation of an extension module from the compiled pypy-c. + + - Writing ctypes implementations of modules to be used by the above + tool. + + - Experimenting and improving performance of our garbage collectors. + + - Experiment with PyPy flexibility or other aspects of the implementation. + + - Possibly experiment with writing modules translatable for use both + in PyPy and CPython. + + - Whatever participants want to do with PyPy or particular areas + of PyPy (please send suggestions to the mailing list before to allow us to plan and give feedback) From auc at codespeak.net Fri Mar 24 18:45:03 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Fri, 24 Mar 2006 18:45:03 +0100 (CET) Subject: [pypy-svn] r24975 - in pypy/dist/pypy/objspace: . test Message-ID: <20060324174503.AD6991015C@code0.codespeak.net> Author: auc Date: Fri Mar 24 18:45:01 2006 New Revision: 24975 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: implemented aliasing with a ring of vars * simplifies some code * makes some predicates O(1) * is supposed to cure wait_needed illness (but ... not yet) Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Fri Mar 24 18:45:01 2006 @@ -159,60 +159,44 @@ class W_Var(baseobjspace.W_Root, object): def __init__(w_self): - w_self.w_bound_to = None # FIXME : make this a ring - w_self.w_needed = False # is it needed ? + w_self.w_bound_to = w_self # FIXME : making this a ring asap + w_self.w_needed = False # is it needed ... ? def __repr__(w_self): if w_self.w_bound_to: - last = find_last_var_in_chain(w_self) - if last.w_bound_to is not None: - return '<%s@%s>' % (last.w_bound_to, - prettyfy_id(str(id(w_self)))) - return '' % prettyfy_id(str(id(w_self))) - -def find_last_var_in_chain(w_var): - w_curr = w_var - while 1: - w_next = w_curr.w_bound_to - if isinstance(w_next, W_Var): - w_curr = w_next - else: - break - return w_curr + if isinstance(w_self.w_bound_to, W_Var): + return '' % prettyfy_id(str(id(w_self))) + return '<%s@%s>' % (w_self.w_bound_to, + prettyfy_id(str(id(w_self)))) def newvar(space): return W_Var() app_newvar = gateway.interp2app(newvar) - -def wait(space, w_self, w_caller=None): +def wait(space, w_self): while 1: if not isinstance(w_self, W_Var): return w_self - w_last = find_last_var_in_chain(w_self) - w_obj = w_last.w_bound_to - if w_obj is None: - # XXX here we would have to suspend the current thread + print " :wait", w_self + if space.is_true(is_free(space, w_self)): if not have_uthreads(): raise OperationError(space.w_RuntimeError, space.wrap("trying to perform an operation on an unbound variable")) else: # notify wait_needed clients, give them a chance to run w_self.w_needed = True - need_waiters = schedule_state.pop_blocked_byneed_on(w_self) - for waiter in need_waiters: - schedule_state.add_to_runnable(waiter) + for w_alias in aliases(space, w_self): + need_waiters = schedule_state.pop_blocked_byneed_on(w_alias) + for waiter in need_waiters: + schedule_state.add_to_runnable(waiter) # set curr thread to blocked, switch to runnable thread current = get_current_coroutine() - schedule_state.add_to_blocked(w_last, current) + schedule_state.add_to_blocked(w_self, current) while schedule_state.have_runnable_threads(): next_coro = schedule_state.pop_runnable_thread() if next_coro.is_alive(): - #print " waiter is switching" - try: - next_coro.switch() - except: - if w_caller: print "Wait", w_caller + print " :waiter is switching" + next_coro.switch() #print " waiter is back" # hope there is a value here now break @@ -220,17 +204,7 @@ raise OperationError(space.w_RuntimeError, space.wrap("blocked on variable, but no uthread that can bind it")) else: - # actually attach the object directly to each variable - # to remove indirections - w_curr = w_self - while 1: - assert isinstance(w_curr, W_Var) - w_next = w_curr.w_bound_to - if not isinstance(w_next, W_Var): - break - w_curr.w_bound_to = w_obj - w_curr = w_next - return w_obj + return w_self.w_bound_to app_wait = gateway.interp2app(wait) def wait_needed(space, w_self): @@ -238,23 +212,22 @@ if not isinstance(w_self, W_Var): raise OperationError(space.w_RuntimeError, space.wrap("wait_needed operates only on logic variables")) - w_last = find_last_var_in_chain(w_self) - w_obj = w_last.w_bound_to - if w_obj is None: + print " :needed", w_self + if space.is_true(is_free(space, w_self)): if w_self.w_needed: break # we're done - # XXX here we would have to FOO the current thread if not have_uthreads(): raise OperationError(space.w_RuntimeError, space.wrap("oh please oh FIXME !")) else: # add current thread to blocked byneed and switch current = get_current_coroutine() - schedule_state.add_to_blocked_byneed(w_self, current) + for w_alias in aliases(space, w_self): + schedule_state.add_to_blocked_byneed(w_alias, current) while schedule_state.have_runnable_threads(): next_coro = schedule_state.pop_runnable_thread() if next_coro.is_alive(): - #print " byneed is switching" + print " :needed is switching" next_coro.switch() #print " byneed is back" # there might be some need right now @@ -271,53 +244,82 @@ #-- PREDICATES -------------------- +def is_aliased(space, w_var): # FIXME: this appears to block + if space.is_true(space.is_nb_(w_var.w_bound_to, w_var)): + return space.newbool(False) + return space.newbool(True) +app_is_aliased = gateway.interp2app(is_aliased) + def is_free(space, w_var): - # XXX make me O(1) if not isinstance(w_var, W_Var): return space.newbool(False) - w_last = find_last_var_in_chain(w_var) - return space.newbool(space.is_w(w_last.w_bound_to, None)) + return space.newbool(isinstance(w_var.w_bound_to, W_Var)) app_is_free = gateway.interp2app(is_free) def is_bound(space, w_var): - # XXX make me O(1) - # FIXME (i'm unreliable, where is_free is not) - if space.is_true(is_free(space, w_var)): - return space.newbool(False) - else: - return space.newbool(True) + return space.newbool(not space.is_true(is_free(space, w_var))) app_is_bound = gateway.interp2app(is_bound) -def is_alias(space, w_var1, w_var2): + +def alias_of(space, w_var1, w_var2): # FIXME: appears to block assert space.is_true(is_free(space, w_var1)) assert space.is_true(is_free(space, w_var2)) # w_var2 could be a right-alias of w_var2 # or the other way around - a = _right_alias(space, w_var1, w_var2) - b = _right_alias(space, w_var2, w_var1) - return space.newbool(a or b) -app_is_alias = gateway.interp2app(is_alias) - -def _right_alias(space, w_var1, w_var2): - """checks wether a var is in the alias chain of another""" - w_curr = w_var1.w_bound_to - while w_curr != None: - if space.is_true(space.is_nb_(w_curr, w_var2)): - return True - w_curr = w_curr.w_bound_to - return False + w_curr = w_var1 + while 1: + w_next = w_curr.w_bound_to + if space.is_true(space.is_nb_(w_next, w_var2)): + return space.newbool(True) + if space.is_true(space.is_nb_(w_next, w_var1)): + break + w_curr = w_next + return space.newbool(False) +app_alias_of = gateway.interp2app(alias_of) #-- HELPERS ---------------------- +def disp(space, w_var): + print w_var +app_disp = gateway.interp2app(disp) + +def disp_aliases(space, w_var): + print "Aliases of ", w_var, "are", + for w_al in aliases(space, w_var): + print w_al, + print + def deref(space, w_var): """gets the value of a bound variable user has to ensure boundness of the var""" assert isinstance(w_var, W_Var) - # FIXME don't need to walk the chain - return find_last_var_in_chain(w_var).w_bound_to + return w_var.w_bound_to + +def aliases(space, w_var): + """return the aliases of a var, including itself""" + al = [] + w_curr = w_var + while 1: + w_next = w_curr.w_bound_to + al.append(w_curr) + if space.is_true(space.is_nb_(w_next, w_var)): + break + w_curr = w_next + return al + +def get_ring_tail(space, w_start): + """returns the last var of a ring of aliases""" + w_curr = w_start + while 1: + w_next = w_curr.w_bound_to + if space.is_true(space.is_nb_(w_next, w_start)): + return w_curr + w_curr = w_next + def fail(space, w_obj1, w_obj2): + """raises a specific exception for bind/unify""" print "can't unify", w_obj1, w_obj2 raise OperationError(space.w_RuntimeError, space.wrap("UnificationFailure")) @@ -332,24 +334,18 @@ l = len(a_str) - 1 return a_str[l-3:l] -def aliases(space, w_var): - al = [] - w_curr = w_var - while w_curr is not None: - al.append(w_curr) - w_curr = w_curr.w_bound_to - return al - def wait_two(space, w_1, w_2): """waits until one out of two logic variables - becomes bound, then tells which one""" - w_v = newvar(space) + becomes bound, then tells which one, + with a bias toward the first if both are + suddenly bound""" + w_V = newvar(space) def sleep(space, w_var): wait(space, w_var) - bind(space, w_var, space.newint(1)) + bind(space, w_V, space.newint(1)) uthread(sleep, space, w_1) uthread(sleep, space, w_2) - wait(space, w_c) + wait(space, w_V) if space.is_true(is_free(space, w_2)): return space.newint(1) return space.newint(2) @@ -361,51 +357,86 @@ 2. assign unbound var to bound var 3. assign value to self """ - print "bind", w_var, w_obj + print " :bind", w_var, w_obj assert isinstance(w_var, W_Var) if isinstance(w_obj, W_Var): if space.is_true(is_bound(space, w_var)): if space.is_true(is_bound(space, w_obj)): - unify(space, - deref(space, w_var), - deref(space, w_obj)) - _assign(space, w_obj, deref(space, w_var)) + return unify(space, #FIXME, should be unify bizness + deref(space, w_var), + deref(space, w_obj)) + return _assign(space, w_obj, deref(space, w_var)) elif space.is_true(is_bound(space, w_obj)): - _assign(space, w_var, deref(space, w_obj)) + return _assign(space, w_var, deref(space, w_obj)) else: # 1. both are unbound - _alias(space, w_var, w_obj) + return _alias(space, w_var, w_obj) else: # 3. w_obj is a value if space.is_true(is_free(space, w_var)): - _assign(space, w_var, w_obj) - unify(space, deref(space, w_var), w_obj) + return _assign(space, w_var, w_obj) + return unify(space, deref(space, w_var), w_obj) app_bind = gateway.interp2app(bind) def _assign(space, w_var, w_val): + print " :assign", w_var, w_val, '[', w_curr = w_var - while w_curr is not None: + ass_count = 0 + while 1: w_next = w_curr.w_bound_to w_curr.w_bound_to = w_val - # awake the blocked threads + print w_curr, + ass_count += 1 + # notify the blocked threads to_awake = schedule_state.pop_blocked_on(w_curr) for thread in to_awake: schedule_state.add_to_runnable(thread) + if space.is_true(space.is_nb_(w_next, w_var)): + break # switch to next w_curr = w_next + print "] (to", ass_count, "aliases)" return space.w_None def _alias(space, w_v1, w_v2): """appends one var to the alias chain of another user must ensure freeness of both vars""" + print " :alias", w_v1, w_v2 if space.is_true(space.is_nb_(w_v1, w_v2)): return space.w_None - last = find_last_var_in_chain(w_v1) - last.w_bound_to = w_v2 + if space.is_true(is_aliased(space, w_v1)): + if space.is_true(is_aliased(space, w_v2)): + return _merge_aliases(space, w_v1, w_v2) + return _add_to_aliases(space, w_v1, w_v2) + if space.is_true(is_aliased(space, w_v2)): + return _add_to_aliases(space, w_v2, w_v1) + # we have two unaliased vars + w_v1.w_bound_to = w_v2 + w_v2.w_bound_to = w_v1 + return space.w_None + +def _add_to_aliases(space, w_v1, w_v2): + print " :add to aliases", w_v1, w_v2 + w_tail = w_v1.w_bound_to + w_v1.w_bound_to = w_v2 + w_v2.w_bound_to = w_tail + disp_aliases(space, w_v1) + disp_aliases(space, w_v2) + return space.w_None + +def _merge_aliases(space, w_v1, w_v2): + print " :merge aliases", w_v1, w_v2 + # first get the tail of both sets + w_tail1 = get_ring_tail(space, w_v1) + w_tail2 = get_ring_tail(space, w_v2) + w_tail1.w_bound_to = w_v2 + w_tail2.w_bound_to = w_v1 + disp_aliases(space, w_v1) + disp_aliases(space, w_v2) return space.w_None #-- UNIFY ------------------------- def unify(space, w_x, w_y): - print "unify", w_x, w_y + print " :unify", w_x, w_y check_and_memoize_pair(space, w_x, w_y) if not isinstance(w_x, W_Var): if not isinstance(w_y, W_Var): @@ -442,7 +473,7 @@ return bind(space, w_x, w_y) def _unify_values(space, w_v1, w_v2): - print " unify values", w_v1, w_v2 + print " :unify values", w_v1, w_v2 # unify object of the same type ... FIXME if not space.is_w(space.type(w_v1), space.type(w_v2)): @@ -458,7 +489,7 @@ return space.w_None def _unify_iterables(space, w_i1, w_i2): - print " unify iterables", w_i1, w_i2 + print " :unify iterables", w_i1, w_i2 # assert lengths if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): fail(space, w_i1, w_i2) @@ -539,7 +570,7 @@ return space.newbool(True) if space.is_true(is_free(space, w_obj1)): if space.is_true(is_free(space, w_obj2)): - if space.is_true(is_alias(space, w_obj1, w_obj2)): + if space.is_true(alias_of(space, w_obj1, w_obj2)): return space.newbool(True) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return eq @@ -557,22 +588,23 @@ return space.newbool(0) if space.is_true(is_free(space, w_obj1)): if space.is_true(is_free(space, w_obj2)): - if space.is_true(is_alias(space, w_obj1, w_obj2)): + if space.is_true(alias_of(space, w_obj1, w_obj2)): return space.newbool(0) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return cmp def neproxy(space, parentfn): def ne(w_obj1, w_obj2): - if space.is_true(is_free(space, w_obj1)) and \ - space.is_true(is_free(space, w_obj2)): - w_var1 = find_last_var_in_chain(w_obj1) - w_var2 = find_last_var_in_chain(w_obj2) - if w_var1 is w_var2: # hmmm - return space.w_False + if space.is_true(space.is_nb_(w_obj1, w_obj2)): + return space.newbool(False) + if space.is_true(is_free(space, w_obj1)): + if space.is_true(is_free(space, w_obj2)): + if space.is_true(alias_of(space, w_obj1, w_obj2)): + return space.newbool(False) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return ne + def proxymaker(space, opname, parentfn): if opname == "eq": return eqproxy(space, parentfn) @@ -587,7 +619,7 @@ proxy = None elif nb_args == 1: def proxy(w1, *extra): - w1 = wait(space, w1, parentfn) + w1 = wait(space, w1) return parentfn(w1, *extra) elif nb_args == 2: def proxy(w1, w2, *extra): @@ -610,16 +642,21 @@ # for now, always make up a wrapped StdObjSpace from pypy.objspace import std space = std.Space(*args, **kwds) - space.is_nb_ = space.is_ # capture the original is_ op + is_nb_ = space.is_ # capture the original is_ op (?) patch_space_in_place(space, 'logic', proxymaker) + space.is_nb_ = is_nb_ space.setitem(space.builtin.w_dict, space.wrap('newvar'), space.wrap(app_newvar)) space.setitem(space.builtin.w_dict, space.wrap('is_free'), space.wrap(app_is_free)) space.setitem(space.builtin.w_dict, space.wrap('is_bound'), space.wrap(app_is_bound)) - space.setitem(space.builtin.w_dict, space.wrap('is_alias'), - space.wrap(app_is_alias)) + space.setitem(space.builtin.w_dict, space.wrap('alias_of'), + space.wrap(app_alias_of)) + space.setitem(space.builtin.w_dict, space.wrap('is_aliased'), + space.wrap(app_is_aliased)) + space.setitem(space.builtin.w_dict, space.wrap('disp'), + space.wrap(app_disp)) space.setitem(space.builtin.w_dict, space.wrap('bind'), space.wrap(app_bind)) space.setitem(space.builtin.w_dict, space.wrap('unify'), Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Fri Mar 24 18:45:01 2006 @@ -12,7 +12,7 @@ assert is_free(X) assert not is_bound(X) bind(X, 1) - assert type(X) == int + assert X == 1 assert not is_free(X) assert is_bound(X) assert is_bound(1) @@ -20,6 +20,11 @@ # FailureException raises(Exception, bind, X, 2) + def test_unify_tuple(self): + X = newvar() + unify(X, (1, (2, None))) + assert X == (1, (2, None)) + def test_bind_to_self(self): X = newvar() assert is_free(X) @@ -34,12 +39,12 @@ unify(X, 1) assert X == 1 - def test_bind_alias(self): + def test_unify_alias(self): X = newvar() Y = newvar() - bind(X, Y) - assert is_alias(X, Y) - assert is_alias(X, Y) + unify(X, Y) + assert alias_of(X, Y) + assert alias_of(Y, X) bind(X, 1) # what about is_alias, then ? assert X == 1 @@ -49,8 +54,8 @@ X = newvar() Y = newvar() unify(X, Y) - assert is_alias(X, Y) - assert is_alias(X, Y) + assert alias_of(X, Y) + assert alias_of(X, Y) unify(X, 1) # what about is_alias, then ? assert X == 1 @@ -98,12 +103,34 @@ for x in [d[5], d[6], d[7][0]]: assert is_bound(d[5]) - def test_unbound_unification_long(self): - l = [newvar() for i in range(40)] - for i in range(39): - bind(l[i], l[i + 1]) - bind(l[20], 1) - for i in range(40): + def test_merge_aliases(self): + X, Y = newvar(), newvar() + Z, W = newvar(), newvar() + unify(X, Y) + assert alias_of(X, Y) + assert alias_of(Y, X) + unify(Z, W) + assert alias_of(Z, W) + assert alias_of(W, Z) + unify(X, W) + vars_ = [X, Y, Z, W] + for V1 in vars_: + assert is_free(V1) + assert is_aliased(V1) + for V2 in vars_: + assert alias_of(V1, V2) + unify(Y, 42) + for V in vars_: + assert V == 42 + + def test_big_alias(self): + l = [newvar() for i in range(20)] + for i in range(19): + bind(l[i], l[i+1]) + for i in range(19): + assert alias_of(l[i], l[i+1]) + bind(l[10], 1) + for i in range(20): assert l[i] == 1 def test_use_unbound_var(self): @@ -116,7 +143,7 @@ X = newvar() Y = newvar() unify(X, Y) - assert is_alias(Y, X) + assert alias_of(Y, X) unify(X, 1) assert X == 1 assert is_bound(Y) @@ -130,7 +157,7 @@ unify(X, Y) assert is_free(X) assert is_free(Y) - assert is_alias(X, Y) + assert alias_of(X, Y) assert X == Y assert not X != Y @@ -151,6 +178,22 @@ def setup_class(cls): cls.space = gettestobjspace('logic') + def test_wait_needed(self): + X = newvar() + + def binder(V): + wait_needed(V) + unify(V, 42) + + def reader(V): + wait(V) + return V + + uthread(reader, X) + uthread(binder, X) + + assert X == 42 + def test_eager_producer_consummer(self): def generate(n, limit): @@ -176,24 +219,24 @@ assert S == 45 - def notest_lazy_producer_consummer(self): + def test_lazy_producer_consummer(self): def lgenerate(n, L): """wait-needed version of generate""" - print "generator waits on L being needed" + print "-- generator waits on L being needed" wait_needed(L) Tail = newvar() - L == (n, Tail) - print "generator bound L to", L + bind(L, (n, Tail)) + print "generator bound L" lgenerate(n+1, Tail) def lsum(L, a, limit): - """this version of sum controls the generator""" - print "sum", a + """this summer controls the generator""" if limit > 0: Head, Tail = newvar(), newvar() - print "sum waiting on L" - L == (Head, Tail) # or Head, Tail == L ? + print "-- sum waiting on L" + wait(L) + unify(L, (Head, Tail)) return lsum(Tail, a+Head, limit-1) else: return a @@ -203,7 +246,9 @@ Y = newvar() T = newvar() uthread(lgenerate, 0, Y) - T == uthread(lsum, Y, 0, 10) + unify(T, uthread(lsum, Y, 0, 3)) print "after" + wait(T) + assert T == 45 print T From stephan at codespeak.net Fri Mar 24 19:51:29 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Fri, 24 Mar 2006 19:51:29 +0100 (CET) Subject: [pypy-svn] r24976 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20060324185129.703A51015E@code0.codespeak.net> Author: stephan Date: Fri Mar 24 19:51:26 2006 New Revision: 24976 Added: pypy/dist/pypy/objspace/std/setobject.py pypy/dist/pypy/objspace/std/settype.py Modified: pypy/dist/pypy/objspace/std/model.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/test/helper.py Log: initial checkin of set/frozenset implementation for std objspace. Since there are no tests yet (yes, I know), the WITHSET switch needs to be set to 'True' in order to use native sets in pypy. Modified: pypy/dist/pypy/objspace/std/model.py ============================================================================== --- pypy/dist/pypy/objspace/std/model.py (original) +++ pypy/dist/pypy/objspace/std/model.py Fri Mar 24 19:51:26 2006 @@ -9,6 +9,7 @@ import pypy.interpreter.special WITHCOMPLEX = False +WITHSET = False class StdTypeModel: @@ -22,6 +23,9 @@ from pypy.objspace.std.floattype import float_typedef if WITHCOMPLEX: from pypy.objspace.std.complextype import complex_typedef + if WITHSET: + from pypy.objspace.std.settype import set_typedef + from pypy.objspace.std.settype import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listtype import list_typedef from pypy.objspace.std.dicttype import dict_typedef @@ -46,6 +50,8 @@ from pypy.objspace.std import floatobject if WITHCOMPLEX: from pypy.objspace.std import complexobject + if WITHSET: + from pypy.objspace.std import setobject from pypy.objspace.std import tupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictobject @@ -68,7 +74,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - #complexobject.W_ComplexObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], dictobject.W_DictObject: [], @@ -87,6 +92,9 @@ } if WITHCOMPLEX: self.typeorder[complexobject.W_ComplexObject] = [] + if WITHSET: + self.typeorder[setobject.W_SetObject] = [] + self.typeorder[setobject.W_FrozensetObject] = [] for type in self.typeorder: self.typeorder[type].append((type, None)) Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Fri Mar 24 19:51:26 2006 @@ -6,7 +6,8 @@ from pypy.interpreter.gateway import PyPyCacheDir from pypy.tool.cache import Cache from pypy.tool.sourcetools import func_with_new_name -from pypy.objspace.std.model import W_Object, UnwrapError, WITHCOMPLEX +from pypy.objspace.std.model import W_Object, UnwrapError +from pypy.objspace.std.model import WITHCOMPLEX, WITHSET from pypy.objspace.std.model import W_ANY, StdObjSpaceMultiMethod, StdTypeModel from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.descroperation import DescrOperation @@ -16,6 +17,19 @@ import os import __builtin__ +#check for sets +try: + s = set() + del s +except NameError: + try: + from sets import Set as set + from sets import ImmutableSet as frozenset + except ImportError: + class DummySet(object):pass + set = DummySet + frozenset = DummySet + _registered_implementations = {} def registerimplementation(implcls): # hint to objspace.std.model to register the implementation class @@ -285,15 +299,25 @@ return self.call_function(c, self.wrap(x.real), self.wrap(x.imag)) - # SD disable for native complex #if isinstance(x, complex): # XXX is this right? YYY no, this is wrong right now (CT) # ZZZ hum, seems necessary for complex literals in co_consts (AR) - c = self.builtin.get('complex') + # c = self.builtin.get('complex') # return self.call_function(c, # self.wrap(x.real), # self.wrap(x.imag)) + + if isinstance(x, set): + if WITHSET: + wrappeditems = [self.wrap(item) for item in x] + return W_SetObject(self, wrappeditems) + + if isinstance(x, frozenset): + if WITHSET: + wrappeditems = [self.wrap(item) for item in x] + return W_FrozensetObject(self, wrappeditems) + if x is __builtin__.Ellipsis: # '__builtin__.Ellipsis' avoids confusion with special.Ellipsis return self.w_Ellipsis @@ -340,6 +364,13 @@ def newcomplex(self, realval, imagval): return W_ComplexObject(self, realval, imagval) + if WITHSET: + def newset(self, list_w): + return W_SetObject(self, list_w) + + def newfrozenset(self, list_w): + return W_FrozensetObject(self, list_w) + def newlong(self, val): # val is an int return W_LongObject.fromint(self, val) Added: pypy/dist/pypy/objspace/std/setobject.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/std/setobject.py Fri Mar 24 19:51:26 2006 @@ -0,0 +1,161 @@ +from pypy.objspace.std.objspace import W_Object, OperationError +from pypy.objspace.std.objspace import registerimplementation, register_all +from pypy.objspace.std.model import WITHSET +from pypy.objspace.std.stdtypedef import StdObjSpaceMultiMethod +from pypy.rpython.objectmodel import r_dict +from pypy.interpreter import gateway + +def _set_init(w_self, space, wrappeditems): + W_Object.__init__(w_self, space) + w_self.data = data = r_dict(space.eq_w, space.hash_w) + if space.is_true(space.isinstance(wrappeditems, space.w_frozenset)): + data.update(wrappeditems.data) + elif space.is_true(space.isinstance(wrappeditems, space.w_set)): + data.update(wrappeditems.data) + else: + iterable_w = space.unpackiterable(wrappeditems) + for w_item in iterable_w: + w_self.data[w_item] = space.w_True + + +class W_SetObject(W_Object): + from pypy.objspace.std.settype import set_typedef as typedef + + def __init__(w_self, space, wrappeditems): + _set_init(w_self, space, wrappeditems) + + def __repr__(w_self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in w_self.data.keys()] + return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) + +class W_FrozensetObject(W_Object): + from pypy.objspace.std.settype import frozenset_typedef as typedef + + def __init__(w_self, space, wrappeditems): + _set_init(w_self, space, wrappeditems) + +registerimplementation(W_SetObject) +registerimplementation(W_FrozensetObject) + +app = gateway.applevel(""" + def and__Set_Set(s, o): + return s.intersection(o) + + def ne__Set_Set(s, o): + return not s == o + + def ge__Set_Set(s, o): + return s.issuperset(o) + + def gt__Set_Set(s, o): + return s != o and s.issuperset(o) + + def le__Set_Set(s, o): + return s.issubset(o) + + def lt__Set_Set(s, o): + return s != o and s.issubset(o) + + def cmp__Set_Set(s, o): + raise TypeError('cannot compare sets using cmp()') + + def or__Set_Set(s, o): + return s.union(o) + + def xor__Set_Set(s, o): + return s.symmetric_difference(o) + + def repr__Set(s): + return 'set(%s)' % [x for x in s] + + def repr__Frozenset(s): + return 'frozenset(%s)' % [x for x in s] + + def sub__Set_Set(s, o): + return s.difference(o) + + def isub__Set_Set(s, o): + s.difference_update(o) + return s + + def ior__Set_Set(s, o): + s.update(o) + return s + + def iand__Set_Set(s, o): + s.intersection_update(o) + return s + + def ixor__Set_Set(s, o): + s.symmetric_difference_update(o) + return s + +""", filename=__file__) + +and__Set_Set = app.interphook("and__Set_Set") +and__Set_Frozenset = and__Set_Set +and__Frozenset_Set = and__Set_Set +and__Frozenset_Frozenset = and__Set_Set + +ne__Set_Set = app.interphook("ne__Set_Set") +ne__Set_Frozenset = ne__Set_Set +ne__Frozenset_Set = ne__Set_Set +ne__Frozenset_Frozenset = ne__Set_Set + +ge__Set_Set = app.interphook("ge__Set_Set") +ge__Set_Frozenset = ge__Set_Set +ge__Frozenset_Set = ge__Set_Set +ge__Frozenset_Frozenset = ge__Set_Set + +le__Set_Set = app.interphook("le__Set_Set") +le__Set_Frozenset = le__Set_Set +le__Frozenset_Set = le__Set_Set +le__Frozenset_Frozenset = le__Set_Set + +gt__Set_Set = app.interphook("gt__Set_Set") +gt__Set_Frozenset = gt__Set_Set +gt__Frozenset_Set = gt__Set_Set +gt__Frozenset_Frozenset = gt__Set_Set + +lt__Set_Set = app.interphook("lt__Set_Set") +lt__Set_Frozenset = lt__Set_Set +lt__Frozenset_Set = lt__Set_Set +lt__Frozenset_Frozenset = lt__Set_Set + +cmp__Set_Set = app.interphook("cmp__Set_Set") +cmp__Set_Frozenset = cmp__Set_Set +cmp__Frozenset_Frozenset = cmp__Set_Set +cmp__Frozenset_Set = cmp__Set_Set + +or__Set_Set = app.interphook("or__Set_Set") +or__Set_Frozenset = or__Set_Set +or__Frozenset_Set = or__Set_Set +or__Frozenset_Frozenset = or__Set_Set + +xor__Set_Set = app.interphook("xor__Set_Set") +xor__Set_Frozenset = xor__Set_Set +xor__Frozenset_Set = xor__Set_Set +xor__Frozenset_Frozenset = xor__Set_Set + +repr__Set = app.interphook('repr__Set') +repr__Frozenset = app.interphook('repr__Frozenset') + +sub__Set_Set = app.interphook('sub__Set_Set') +sub__Set_Frozenset = sub__Set_Set +sub__Frozenset_Set = sub__Set_Set +sub__Frozenset_Frozenset = sub__Set_Set + +inplace_sub__Set_Set = app.interphook('isub__Set_Set') +inplace_sub__Set_Frozenset = inplace_sub__Set_Set + +inplace_or__Set_Set = app.interphook('ior__Set_Set') +inplace_or__Set_Frozenset = inplace_or__Set_Set + +inplace_and__Set_Set = app.interphook('iand__Set_Set') +inplace_and__Set_Frozenset = inplace_and__Set_Set + +inplace_xor__Set_Set = app.interphook('ixor__Set_Set') +inplace_xor__Set_Frozenset = inplace_xor__Set_Set + +register_all(vars()) Added: pypy/dist/pypy/objspace/std/settype.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/std/settype.py Fri Mar 24 19:51:26 2006 @@ -0,0 +1,310 @@ +from pypy.interpreter.error import OperationError +from pypy.objspace.std.objspace import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef, newmethod +from pypy.objspace.std.stdtypedef import StdObjSpaceMultiMethod +from pypy.interpreter.gateway import NoneNotWrapped +from pypy.interpreter import gateway +from pypy.objspace.std.model import WITHSET + +def descr__set__new__(space, w_settype, w_iterable=NoneNotWrapped): + from pypy.objspace.std.setobject import W_SetObject + if w_iterable is None: + w_iterable = space.newtuple([]) + elif (space.is_w(w_settype, space.w_set) and + space.is_w(space.type(w_iterable), space.w_set)): + return w_iterable + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space, w_iterable) + + return w_obj + +def descr__frozenset__new__(space, w_frozensettype, w_iterable=NoneNotWrapped): + from pypy.objspace.std.setobject import W_FrozensetObject + if w_iterable is None: + w_iterable = space.newtuple([]) + elif (space.is_w(w_frozensettype, space.w_frozenset) and + space.is_w(space.type(w_iterable), space.w_frozenset)): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + + return w_obj + +# some helper functions + +def _extract_data_dict(space, w_left, w_right): + assert (space.is_true(space.isinstance(w_left, space.w_set)) or + space.is_true(space.isinstance(w_left, space.w_frozenset))) + if not (space.is_true(space.isinstance(w_right, space.w_set)) or + space.is_true(space.isinstance(w_right, space.w_frozenset))): + w_right = space.newset(w_right) + + return w_left.data, w_right.data + +def _dict_to_set(space, rpdict): + return space.newset(space.newtuple(rpdict.keys())) + +def _dict_to_frozenset(space, rpdict): + return space.newfrozenset(space.newtuple(rpdict.keys())) + +# helper functions for set operation on dicts + +def _union_dict(space, ldict, rdict, isupdate): + if isupdate: + ld = ldict + else: + ld = ldict.copy() + ld.update(rdict) + return ld, rdict + +def _difference_dict(space, ldict, rdict, isupdate): + if isupdate: + ld = ldict + else: + ld = ldict.copy() + del_list_w = [] + for w_key in ld.iterkeys(): + if w_key in rdict: + del_list_w.append(w_key) + for w_key in del_list_w: + del ld[w_key] + + return ld, rdict + +def _intersection_dict(space, ldict, rdict, isupdate): + if isupdate: + ld = ldict + else: + ld = ldict.copy() + del_list_w = [] + for w_key in ld.iterkeys(): + if w_key not in rdict: + del_list_w.append(w_key) + + for w_key in del_list_w: + del ld[w_key] + + return ld, rdict + + +def _symmetric_difference_dict(space, ldict, rdict, isupdate): + if isupdate: + ld = ldict + else: + ld = ldict.copy() + del_list_w = [] + add_list_w = [] + for w_key in ld.iterkeys(): + if w_key in rdict: + del_list_w.append(w_key) + + for w_key in rdict.iterkeys(): + if w_key not in ld: + add_list_w.append(w_key) + + for w_key in del_list_w: + del ld[w_key] + + for w_key in add_list_w: + ld[w_key] = space.w_True + + return ld, rdict + +def descr_update(space, w_self, w_iterable): + """Update a set with the union of itself and another.""" + ld, rd = _extract_data_dict(space, w_self, w_iterable) + new_ld, rd = _union_dict(space, ld, rd, True) + return space.w_None + +def descr_add(space, w_self, w_other): + """Add an element to a set. + + This has no effect if the element is already present. + """ + + w_self.data[w_other] = space.w_True + +def descr_copy_s(space, w_self): + return space.newset(w_self) + +def descr_copy_fs(space, w_self): + return space.newfrozenset(w_self) + +def descr_clear(space, w_self): + w_self.data.clear() + +def descr_difference_s(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _difference_dict(space, ld, rd, False) + return _dict_to_set(space, new_ld) + +def descr_difference_fs(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _difference_dict(space, ld, rd, False) + return _dict_to_frozenset(space, new_ld) + + +def descr_difference_update(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _difference_dict(space, ld, rd, True) + return space.w_None + +def descr__set__eq__(space, w_self, w_other): + if space.is_w(w_self, w_other): + return space.w_True + + if len(w_self.data) != len(w_other.data): + return space.w_False + + for w_key in w_self.data.iterkeys(): + if w_key not in w_other.data: + return space.w_False + return space.w_True + +def descr__set__contains__(space, w_self, w_other): + return space.newbool(w_other in w_self.data) + +def descr_issubset(space, w_self, w_other): + if space.is_w(w_self, w_other): + return space.w_True + + if len(w_self.data) > len(w_other.data): + return space.w_False + + for w_key in w_self.data: + if w_key not in w_other.data: + return space.w_False + return space.w_True + +def descr_issuperset(space, w_self, w_other): + if space.is_w(w_self, w_other): + return space.w_True + + if len(w_self.data) < len(w_other.data): + return space.w_False + + for w_key in w_other.data: + if w_key not in w_self.data: + return space.w_False + return space.w_True + +def descr_discard(space, w_self, w_item): + if w_item in w_self.data: + del w_self.data[w_item] + +def descr_remove(space, w_self, w_item): + try: + del w_self.data[w_item] + except KeyError: + raise OperationError(space.w_KeyError, + space.call_method(w_item,'__repr__')) + +def descr__set__hash__(space, w_self): + raise OperationError(space.w_TypeError, + space.wrap('set objects are unhashable')) + +def descr_pop(space, w_self): + if len(w_self.data) == 0: + raise OperationError(space.w_KeyError, + space.wrap('pop from an empty set')) + w_keys = w_self.data.keys() + w_value = w_keys[0] + del w_self.data[w_value] + + return w_value + +def descr_intersection_s(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _intersection_dict(space, ld, rd, False) + return _dict_to_set(space, new_ld) + +def descr_intersection_fs(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _intersection_dict(space, ld, rd, False) + return _dict_to_frozenset(space, new_ld) + +def descr_intersection_update(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _intersection_dict(space, ld, rd, True) + return space.w_None + +def descr_symmetric_difference_s(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _symmetric_difference_dict(space, ld, rd, False) + return _dict_to_set(space, new_ld) + +def descr_symmetric_difference_fs(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _symmetric_difference_dict(space, ld, rd, False) + return _dict_to_frozenset(space, new_ld) + +def descr_symmetric_difference_update(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _symmetric_difference_dict(space, ld, rd, True) + return space.w_None + +def descr_union_s(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _union_dict(space, ld, rd, False) + return _dict_to_set(space, new_ld) + +def descr_union_fs(space, w_self, w_other): + ld, rd = _extract_data_dict(space, w_self, w_other) + new_ld, rd = _union_dict(space, ld, rd, False) + return _dict_to_frozenset(space, new_ld) + +def descr__set__len__(space, w_self): + return space.newint(len(w_self.data)) + +def descr__set__iter__(space, w_self): + from pypy.objspace.std import iterobject + return iterobject.W_SeqIterObject(space, + space.newtuple(w_self.data.keys())) + +set_typedef = StdTypeDef("set", + __doc__ = """set(iterable) --> set object + +Build an unordered collection.""", + __new__ = newmethod(descr__set__new__), + __eq__ = newmethod(descr__set__eq__), + __contains__ = newmethod(descr__set__contains__), + __len__ = newmethod(descr__set__len__), + __iter__ = newmethod(descr__set__iter__), + __hash__ = newmethod(descr__set__hash__), + add = newmethod(descr_add), + clear = newmethod(descr_clear), + copy = newmethod(descr_copy_s), + difference = newmethod(descr_difference_s), + difference_update = newmethod(descr_difference_update), + discard = newmethod(descr_discard), + intersection = newmethod(descr_intersection_s), + intersection_update = newmethod(descr_intersection_update), + issubset = newmethod(descr_issubset), + issuperset = newmethod(descr_issuperset), + pop = newmethod(descr_pop), + remove = newmethod(descr_remove), + symmetric_difference = newmethod(descr_symmetric_difference_s), + symmetric_difference_update = newmethod(descr_symmetric_difference_update), + union = newmethod(descr_union_s), + update = newmethod(descr_update), + ) + +#set_typedef.registermethods(globals()) + +frozenset_typedef = StdTypeDef("frozenset", + __doc__ = """frozenset(iterable) --> frozenset object + +Build an immutable unordered collection.""", + __new__ = newmethod(descr__frozenset__new__), + __eq__ = newmethod(descr__set__eq__), + __contains__ = newmethod(descr__set__contains__), + __len__ = newmethod(descr__set__len__), + __iter__ = newmethod(descr__set__iter__), + copy = newmethod(descr_copy_fs), + difference = newmethod(descr_difference_fs), + intersection = newmethod(descr_intersection_fs), + issubset = newmethod(descr_issubset), + issuperset = newmethod(descr_issuperset), + symmetric_difference = newmethod(descr_symmetric_difference_fs), + union = newmethod(descr_union_fs), + ) Modified: pypy/dist/pypy/objspace/std/test/helper.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/helper.py (original) +++ pypy/dist/pypy/objspace/std/test/helper.py Fri Mar 24 19:51:26 2006 @@ -1,5 +1,3 @@ -EPS = 1e-9 - def raises(excp, func, *args): try: func(*args) @@ -12,6 +10,13 @@ def assertNotEqual(a, b): assert a != b +def assertIs(a, b): + assert a is b + +# complex specific tests + +EPS = 1e-9 + def assertAlmostEqual(a, b): if isinstance(a, complex): if isinstance(b, complex): @@ -44,8 +49,6 @@ assertCloseAbs(x.real, y.real, eps) assertCloseAbs(x.imag, y.imag, eps) -def assertIs(a, b): - assert a is b def check_div(x, y): """Compute complex z=x*y, and check that z/x==y and z/y==x.""" From pedronis at codespeak.net Fri Mar 24 22:23:49 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 24 Mar 2006 22:23:49 +0100 (CET) Subject: [pypy-svn] r24978 - pypy/dist/pypy/rpython/test Message-ID: <20060324212349.5EF791012D@code0.codespeak.net> Author: pedronis Date: Fri Mar 24 22:23:48 2006 New Revision: 24978 Modified: pypy/dist/pypy/rpython/test/test_rpbc.py Log: in-progress test on disjoint access pbcs Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Fri Mar 24 22:23:48 2006 @@ -1363,6 +1363,32 @@ res = interp.eval_graph(ll_h_graph, [None, c_f, c_a]) assert typeOf(res) == A_repr.lowleveltype +def test_disjoint_pbcs(): + py.test.skip("in-progress") + class Frozen(object): + def __init__(self, v): + self.v = 2 + def _freeze_(self): + return True + + f1 = Frozen(2) + f2 = Frozen(3) + + def g1(x): + return x.v + def g2(y): + return y.v + def h(x): + return x != None + + def f(): + a = g1(f1) + b = g2(f2) + return h(f1)+h(f2)+a+b + + res = interpret(f, []) + + assert res == 7 class TestLltype(BaseTestRPBC): From cfbolz at codespeak.net Fri Mar 24 23:08:28 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 24 Mar 2006 23:08:28 +0100 (CET) Subject: [pypy-svn] r24980 - in pypy/branch/explicit-exceptions/translator/c: . src Message-ID: <20060324220828.238FA1012A@code0.codespeak.net> Author: cfbolz Date: Fri Mar 24 23:08:22 2006 New Revision: 24980 Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py pypy/branch/explicit-exceptions/translator/c/gc.py pypy/branch/explicit-exceptions/translator/c/src/address.h pypy/branch/explicit-exceptions/translator/c/src/char.h pypy/branch/explicit-exceptions/translator/c/src/float.h pypy/branch/explicit-exceptions/translator/c/src/int.h pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h pypy/branch/explicit-exceptions/translator/c/src/mem.h pypy/branch/explicit-exceptions/translator/c/src/pyobj.h pypy/branch/explicit-exceptions/translator/c/src/support.h pypy/branch/explicit-exceptions/translator/c/src/trace.h pypy/branch/explicit-exceptions/translator/c/src/unichar.h pypy/branch/explicit-exceptions/translator/c/stackless.py Log: remove the error label from all C code, especially the macros -- to raise an exception use RPyRaiseException and make sure that no code is executed afterwards (if it is a macro, otherwise you can return of course). Modified: pypy/branch/explicit-exceptions/translator/c/funcgen.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/funcgen.py (original) +++ pypy/branch/explicit-exceptions/translator/c/funcgen.py Fri Mar 24 23:08:22 2006 @@ -148,7 +148,7 @@ vanishing_exc_value = self.expr(v) yield 'RPyConvertExceptionToCPython(%s);' % vanishing_exc_value for cleanupop in exc_cleanup_ops: - for line in self.gen_op(cleanupop, 'should_never_be_jumped_to'): + for line in self.gen_op(cleanupop): yield line yield 'return %s; ' % self.error_return_value() @@ -184,7 +184,7 @@ yield '' yield 'block%d:' % myblocknum for i, op in enumerate(block.operations): - for line in self.gen_op(op, "should_never_be_reached"): + for line in self.gen_op(op): yield line if len(block.exits) == 0: assert len(block.inputargs) == 1 @@ -278,20 +278,19 @@ yield line yield 'goto block%d;' % self.blocknum[link.target] - def gen_op(self, op, err): + def gen_op(self, op): macro = 'OP_%s' % op.opname.upper() if op.opname.startswith('gc_'): meth = getattr(self.gcpolicy, macro, None) if meth: - line = meth(self, op, err) + line = meth(self, op) else: meth = getattr(self, macro, None) if meth: - line = meth(op, err) + line = meth(op) if meth is None: lst = [self.expr(v) for v in op.args] lst.append(self.expr(op.result)) - lst.append(err) line = '%s(%s);' % (macro, ', '.join(lst)) if "\n" not in line: yield line @@ -304,43 +303,43 @@ # the C preprocessor cannot handle operations taking a variable number # of arguments, so here are Python methods that do it - def OP_NEWLIST(self, op, err): + def OP_NEWLIST(self, op): args = [self.expr(v) for v in op.args] r = self.expr(op.result) if len(args) == 0: - return 'OP_NEWLIST0(%s, %s);' % (r, err) + return 'OP_NEWLIST0(%s);' % (r, ) else: args.insert(0, '%d' % len(args)) - return 'OP_NEWLIST((%s), %s, %s);' % (', '.join(args), r, err) + return 'OP_NEWLIST((%s), %s);' % (', '.join(args), r) - def OP_NEWDICT(self, op, err): + def OP_NEWDICT(self, op): args = [self.expr(v) for v in op.args] r = self.expr(op.result) if len(args) == 0: - return 'OP_NEWDICT0(%s, %s);' % (r, err) + return 'OP_NEWDICT0(%s);' % (r, ) else: assert len(args) % 2 == 0 args.insert(0, '%d' % (len(args)//2)) - return 'OP_NEWDICT((%s), %s, %s);' % (', '.join(args), r, err) + return 'OP_NEWDICT((%s), %s);' % (', '.join(args), r) - def OP_NEWTUPLE(self, op, err): + def OP_NEWTUPLE(self, op): args = [self.expr(v) for v in op.args] r = self.expr(op.result) args.insert(0, '%d' % len(args)) - return 'OP_NEWTUPLE((%s), %s, %s);' % (', '.join(args), r, err) + return 'OP_NEWTUPLE((%s), %s);' % (', '.join(args), r) - def OP_SIMPLE_CALL(self, op, err): + def OP_SIMPLE_CALL(self, op): args = [self.expr(v) for v in op.args] r = self.expr(op.result) args.append('NULL') - return 'OP_SIMPLE_CALL((%s), %s, %s);' % (', '.join(args), r, err) + return 'OP_SIMPLE_CALL((%s), %s);' % (', '.join(args), r) - def OP_CALL_ARGS(self, op, err): + def OP_CALL_ARGS(self, op): args = [self.expr(v) for v in op.args] r = self.expr(op.result) - return 'OP_CALL_ARGS((%s), %s, %s);' % (', '.join(args), r, err) + return 'OP_CALL_ARGS((%s), %s);' % (', '.join(args), r) - def OP_DIRECT_CALL(self, op, err): + def OP_DIRECT_CALL(self, op): # skip 'void' arguments args = [self.expr(v) for v in op.args if self.lltypemap(v) is not Void] line = '%s(%s);' % (args[0], ', '.join(args[1:])) @@ -348,7 +347,7 @@ # skip assignment of 'void' return value r = self.expr(op.result) line = '%s = %s' % (r, line) - check = self.check_directcall_result(op, err) + check = self.check_directcall_result(op) if check: return line + '\n' + check return line @@ -357,7 +356,7 @@ # is of type Void, which is removed by OP_DIRECT_CALL OP_INDIRECT_CALL = OP_DIRECT_CALL - def check_directcall_result(self, op, err): + def check_directcall_result(self, op): return None # low-level operations @@ -382,7 +381,7 @@ result = '/* %s */' % result return result - def OP_GETFIELD(self, op, err, ampersand=''): + def OP_GETFIELD(self, op, ampersand=''): assert isinstance(op.args[1], Constant) STRUCT = self.lltypemap(op.args[0]).TO structdef = self.db.gettypedefnode(STRUCT) @@ -391,7 +390,7 @@ self.expr(op.args[0]), fieldname)) - def OP_SETFIELD(self, op, err): + def OP_SETFIELD(self, op): assert isinstance(op.args[1], Constant) STRUCT = self.lltypemap(op.args[0]).TO structdef = self.db.gettypedefnode(STRUCT) @@ -399,52 +398,52 @@ return self.generic_set(op, '%s->%s' % (self.expr(op.args[0]), fieldname)) - def OP_GETSUBSTRUCT(self, op, err): - return self.OP_GETFIELD(op, err, ampersand='&') + def OP_GETSUBSTRUCT(self, op): + return self.OP_GETFIELD(op, ampersand='&') - def OP_GETARRAYSIZE(self, op, err): + def OP_GETARRAYSIZE(self, op): return '%s = %s->length;' % (self.expr(op.result), self.expr(op.args[0])) - def OP_GETARRAYITEM(self, op, err): + def OP_GETARRAYITEM(self, op): return self.generic_get(op, '%s->items[%s]' % (self.expr(op.args[0]), self.expr(op.args[1]))) - def OP_SETARRAYITEM(self, op, err): + def OP_SETARRAYITEM(self, op): return self.generic_set(op, '%s->items[%s]' % (self.expr(op.args[0]), self.expr(op.args[1]))) - def OP_GETARRAYSUBSTRUCT(self, op, err): + def OP_GETARRAYSUBSTRUCT(self, op): return '%s = %s->items + %s;' % (self.expr(op.result), self.expr(op.args[0]), self.expr(op.args[1])) - def OP_PTR_NONZERO(self, op, err): + def OP_PTR_NONZERO(self, op): return '%s = (%s != NULL);' % (self.expr(op.result), self.expr(op.args[0])) - def OP_PTR_ISZERO(self, op, err): + def OP_PTR_ISZERO(self, op): return '%s = (%s == NULL);' % (self.expr(op.result), self.expr(op.args[0])) - def OP_PTR_EQ(self, op, err): + def OP_PTR_EQ(self, op): return '%s = (%s == %s);' % (self.expr(op.result), self.expr(op.args[0]), self.expr(op.args[1])) - def OP_PTR_NE(self, op, err): + def OP_PTR_NE(self, op): return '%s = (%s != %s);' % (self.expr(op.result), self.expr(op.args[0]), self.expr(op.args[1])) - def OP_MALLOC(self, op, err): + def OP_MALLOC(self, op): TYPE = self.lltypemap(op.result).TO typename = self.db.gettype(TYPE) eresult = self.expr(op.result) esize = 'sizeof(%s)' % cdecl(typename, '') - return self.gcpolicy.zero_malloc(TYPE, esize, eresult, err) + return self.gcpolicy.zero_malloc(TYPE, esize, eresult) - def OP_MALLOC_VARSIZE(self, op, err): + def OP_MALLOC_VARSIZE(self, op): TYPE = self.lltypemap(op.result).TO typename = self.db.gettype(TYPE) lenfld = 'length' @@ -464,45 +463,43 @@ result = '' else: itemtype = cdecl(itemtypename, '') - result = 'OP_MAX_VARSIZE(%s, %s, %s);\n' % ( + result = 'OP_MAX_VARSIZE(%s, %s);\n' % ( elength, - itemtype, - err) + itemtype) esize = 'sizeof(%s)-sizeof(%s)+%s*sizeof(%s)' % ( cdecl(typename, ''), itemtype, elength, itemtype) - result += self.gcpolicy.zero_malloc(TYPE, esize, eresult, err) + result += self.gcpolicy.zero_malloc(TYPE, esize, eresult) # ctypes Arrays have no length field if not VARPART._hints.get('nolength', False): result += '\n%s->%s = %s;' % (eresult, lenfld, elength) return result - def OP_FLAVORED_MALLOC(self, op, err): + def OP_FLAVORED_MALLOC(self, op): TYPE = self.lltypemap(op.result).TO typename = self.db.gettype(TYPE) eresult = self.expr(op.result) esize = 'sizeof(%s)' % cdecl(typename, '') flavor = op.args[0].value if flavor == "raw": - return "OP_RAW_MALLOC(%s, %s, %s);" % (esize, eresult, err) + return "OP_RAW_MALLOC(%s, %s);" % (esize, eresult) elif flavor == "stack": - return "OP_STACK_MALLOC(%s, %s, %s);" % (esize, eresult, err) + return "OP_STACK_MALLOC(%s, %s);" % (esize, eresult) else: raise NotImplementedError - def OP_FLAVORED_FREE(self, op, err): + def OP_FLAVORED_FREE(self, op): flavor = op.args[0].value if flavor == "raw": - return "OP_RAW_FREE(%s, %s, %s)" % (self.expr(op.args[1]), - self.expr(op.result), - err) + return "OP_RAW_FREE(%s, %s)" % (self.expr(op.args[1]), + self.expr(op.result)) else: raise NotImplementedError - def OP_CAST_POINTER(self, op, err): + def OP_CAST_POINTER(self, op): TYPE = self.lltypemap(op.result) typename = self.db.gettype(TYPE) result = [] @@ -517,13 +514,13 @@ OP_CAST_PTR_TO_ADR = OP_CAST_POINTER OP_CAST_ADR_TO_PTR = OP_CAST_POINTER - def OP_CAST_INT_TO_PTR(self, op, err): + def OP_CAST_INT_TO_PTR(self, op): TYPE = self.lltypemap(op.result) typename = self.db.gettype(TYPE) return "%s = (%s)%s;" % (self.expr(op.result), cdecl(typename, ""), self.expr(op.args[0])) - def OP_SAME_AS(self, op, err): + def OP_SAME_AS(self, op): result = [] TYPE = self.lltypemap(op.result) assert self.lltypemap(op.args[0]) == TYPE @@ -534,15 +531,15 @@ result.append('Py_XINCREF(%s);'%(LOCAL_VAR % op.result.name)) return '\t'.join(result) - def OP_HINT(self, op, err): + def OP_HINT(self, op): hints = op.args[1].value - return '%s\t/* hint: %r */' % (self.OP_SAME_AS(op, err), hints) + return '%s\t/* hint: %r */' % (self.OP_SAME_AS(op), hints) - def OP_KEEPALIVE(self, op, err): # xxx what should be the sematics consequences of this + def OP_KEEPALIVE(self, op): # xxx what should be the sematics consequences of this return "/* kept alive: %s */ ;" % self.expr(op.args[0], special_case_void=False) #address operations - def OP_RAW_STORE(self, op, err): + def OP_RAW_STORE(self, op): addr = self.expr(op.args[0]) TYPE = op.args[1].value offset = self.expr(op.args[2]) @@ -550,7 +547,7 @@ typename = self.db.gettype(TYPE).replace("@", "*") #XXX help! is this the way to do it? return "*(((%(typename)s) %(addr)s ) + %(offset)s) = %(value)s;" % locals() - def OP_RAW_LOAD(self, op, err): + def OP_RAW_LOAD(self, op): addr = self.expr(op.args[0]) TYPE = op.args[1].value offset = self.expr(op.args[2]) Modified: pypy/branch/explicit-exceptions/translator/c/gc.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/gc.py (original) +++ pypy/branch/explicit-exceptions/translator/c/gc.py Fri Mar 24 23:08:22 2006 @@ -45,13 +45,13 @@ def gc_startup_code(self): return [] - def OP_GC_PUSH_ALIVE_PYOBJ(self, funcgen, op, err): + def OP_GC_PUSH_ALIVE_PYOBJ(self, funcgen, op): expr = funcgen.expr(op.args[0]) if expr == 'NULL': return '' return 'Py_XINCREF(%s);' % expr - def OP_GC_POP_ALIVE_PYOBJ(self, funcgen, op, err): + def OP_GC_POP_ALIVE_PYOBJ(self, funcgen, op): expr = funcgen.expr(op.args[0]) return 'Py_XDECREF(%s);' % expr @@ -101,31 +101,30 @@ # zero malloc impl - def zero_malloc(self, TYPE, esize, eresult, err): + def zero_malloc(self, TYPE, esize, eresult): assert TYPE._gcstatus() # we don't really support this - return 'OP_ZERO_MALLOC(%s, %s, %s);' % (esize, - eresult, - err) + return 'OP_ZERO_MALLOC(%s, %s);' % (esize, + eresult) - def OP_GC_CALL_RTTI_DESTRUCTOR(self, funcgen, op, err): + def OP_GC_CALL_RTTI_DESTRUCTOR(self, funcgen, op): args = [funcgen.expr(v) for v in op.args] line = '%s(%s);' % (args[0], ', '.join(args[1:])) return line - def OP_GC_FREE(self, funcgen, op, err): + def OP_GC_FREE(self, funcgen, op): args = [funcgen.expr(v) for v in op.args] return 'OP_FREE(%s);' % (args[0], ) - def OP_GC_FETCH_EXCEPTION(self, funcgen, op, err): + def OP_GC_FETCH_EXCEPTION(self, funcgen, op): result = funcgen.expr(op.result) return ('%s = RPyFetchExceptionValue();\n' 'RPyClearException();') % (result, ) - def OP_GC_RESTORE_EXCEPTION(self, funcgen, op, err): + def OP_GC_RESTORE_EXCEPTION(self, funcgen, op): argh = funcgen.expr(op.args[0]) return 'if (%s != NULL) RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(%s), %s);' % (argh, argh, argh) - def OP_GC__COLLECT(self, funcgen, op, err): + def OP_GC__COLLECT(self, funcgen, op): return '' @@ -179,16 +178,15 @@ def rtti_node_factory(self): return BoehmGcRuntimeTypeInfo_OpaqueNode - def zero_malloc(self, TYPE, esize, eresult, err): + def zero_malloc(self, TYPE, esize, eresult): gcinfo = self.db.gettypedefnode(TYPE).gcinfo assert TYPE._gcstatus() # _is_atomic() depends on this! is_atomic = TYPE._is_atomic() is_varsize = TYPE._is_varsize() - result = 'OP_BOEHM_ZERO_MALLOC(%s, %s, %d, %d, %s);' % (esize, - eresult, - is_atomic, - is_varsize, - err) + result = 'OP_BOEHM_ZERO_MALLOC(%s, %s, %d, %d);' % (esize, + eresult, + is_atomic, + is_varsize) if gcinfo and gcinfo.finalizer: result += ('\nGC_REGISTER_FINALIZER(%s, (GC_finalization_proc)%s, NULL, NULL, NULL);' % (eresult, gcinfo.finalizer)) @@ -218,16 +216,16 @@ yield 'GC_init();' - def OP_GC_FETCH_EXCEPTION(self, funcgen, op, err): + def OP_GC_FETCH_EXCEPTION(self, funcgen, op): result = funcgen.expr(op.result) return ('%s = RPyFetchExceptionValue();\n' 'RPyClearException();') % (result, ) - def OP_GC_RESTORE_EXCEPTION(self, funcgen, op, err): + def OP_GC_RESTORE_EXCEPTION(self, funcgen, op): argh = funcgen.expr(op.args[0]) return 'if (%s != NULL) RPyRaiseException(RPYTHON_TYPE_OF_EXC_INST(%s), %s);' % (argh, argh, argh) - def OP_GC__COLLECT(self, funcgen, op, err): + def OP_GC__COLLECT(self, funcgen, op): return 'GC_gcollect(); GC_invoke_finalizers();' @@ -277,7 +275,7 @@ def pre_gc_code(self): return [] - def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op, err): + def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op): args = [funcgen.expr(v) for v in op.args] return '%s = %s; /* for moving GCs */' % (args[1], args[0]) Modified: pypy/branch/explicit-exceptions/translator/c/src/address.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/address.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/address.h Fri Mar 24 23:08:22 2006 @@ -5,29 +5,29 @@ /*** binary operations ***/ -#define OP_ADR_DELTA(x,y,r,err) r = ((char *)(x) - (char *)(y)) -#define OP_ADR_SUB(x,y,r,err) r = ((char *)(x) - (y)) -#define OP_ADR_ADD(x,y,r,err) r = ((char *)(x) + (y)) - -#define OP_ADR_EQ(x,y,r,err) r = ((x) == (y)) -#define OP_ADR_NE(x,y,r,err) r = ((x) != (y)) -#define OP_ADR_LE(x,y,r,err) r = ((x) <= (y)) -#define OP_ADR_GT(x,y,r,err) r = ((x) > (y)) -#define OP_ADR_LT(x,y,r,err) r = ((x) < (y)) -#define OP_ADR_GE(x,y,r,err) r = ((x) >= (y)) - -#define OP_RAW_MALLOC(size,r,err) \ - r = (void*) calloc(1, size); \ - if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ +#define OP_ADR_DELTA(x,y,r) r = ((char *)(x) - (char *)(y)) +#define OP_ADR_SUB(x,y,r) r = ((char *)(x) - (y)) +#define OP_ADR_ADD(x,y,r) r = ((char *)(x) + (y)) + +#define OP_ADR_EQ(x,y,r) r = ((x) == (y)) +#define OP_ADR_NE(x,y,r) r = ((x) != (y)) +#define OP_ADR_LE(x,y,r) r = ((x) <= (y)) +#define OP_ADR_GT(x,y,r) r = ((x) > (y)) +#define OP_ADR_LT(x,y,r) r = ((x) < (y)) +#define OP_ADR_GE(x,y,r) r = ((x) >= (y)) + +#define OP_RAW_MALLOC(size,r) \ + r = (void*) calloc(1, size); \ + if (r == NULL) FAIL_EXCEPTION( PyExc_MemoryError, "out of memory");\ #ifdef MS_WINDOWS #define alloca _alloca #endif -#define OP_STACK_MALLOC(size,r,err) \ +#define OP_STACK_MALLOC(size,r) \ r = (void*) alloca(size); \ - if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ + if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memory");\ -#define OP_RAW_FREE(x,r,err) free(x); -#define OP_RAW_MEMCOPY(x,y,size,r,err) memcpy(y,x,size); +#define OP_RAW_FREE(x,r) free(x); +#define OP_RAW_MEMCOPY(x,y,size,r) memcpy(y,x,size); Modified: pypy/branch/explicit-exceptions/translator/c/src/char.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/char.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/char.h Fri Mar 24 23:08:22 2006 @@ -6,10 +6,10 @@ /*** binary operations ***/ -#define OP_CHAR_EQ(x,y,r,err) r = ((x) == (y)) -#define OP_CHAR_NE(x,y,r,err) r = ((x) != (y)) -#define OP_CHAR_LE(x,y,r,err) r = ((unsigned char)(x) <= (unsigned char)(y)) -#define OP_CHAR_GT(x,y,r,err) r = ((unsigned char)(x) > (unsigned char)(y)) -#define OP_CHAR_LT(x,y,r,err) r = ((unsigned char)(x) < (unsigned char)(y)) -#define OP_CHAR_GE(x,y,r,err) r = ((unsigned char)(x) >= (unsigned char)(y)) +#define OP_CHAR_EQ(x,y,r) r = ((x) == (y)) +#define OP_CHAR_NE(x,y,r) r = ((x) != (y)) +#define OP_CHAR_LE(x,y,r) r = ((unsigned char)(x) <= (unsigned char)(y)) +#define OP_CHAR_GT(x,y,r) r = ((unsigned char)(x) > (unsigned char)(y)) +#define OP_CHAR_LT(x,y,r) r = ((unsigned char)(x) < (unsigned char)(y)) +#define OP_CHAR_GE(x,y,r) r = ((unsigned char)(x) >= (unsigned char)(y)) Modified: pypy/branch/explicit-exceptions/translator/c/src/float.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/float.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/float.h Fri Mar 24 23:08:22 2006 @@ -5,35 +5,35 @@ /*** unary operations ***/ -#define OP_FLOAT_IS_TRUE(x,r,err) OP_FLOAT_NE(x,0.0,r,err) -#define OP_FLOAT_NEG(x,r,err) r = -x -#define OP_FLOAT_ABS(x,r,err) r = fabs(x) +#define OP_FLOAT_IS_TRUE(x,r) OP_FLOAT_NE(x,0.0,r) +#define OP_FLOAT_NEG(x,r) r = -x +#define OP_FLOAT_ABS(x,r) r = fabs(x) /*** binary operations ***/ -#define OP_FLOAT_EQ(x,y,r,err) r = (x == y) -#define OP_FLOAT_NE(x,y,r,err) r = (x != y) -#define OP_FLOAT_LE(x,y,r,err) r = (x <= y) -#define OP_FLOAT_GT(x,y,r,err) r = (x > y) -#define OP_FLOAT_LT(x,y,r,err) r = (x < y) -#define OP_FLOAT_GE(x,y,r,err) r = (x >= y) +#define OP_FLOAT_EQ(x,y,r) r = (x == y) +#define OP_FLOAT_NE(x,y,r) r = (x != y) +#define OP_FLOAT_LE(x,y,r) r = (x <= y) +#define OP_FLOAT_GT(x,y,r) r = (x > y) +#define OP_FLOAT_LT(x,y,r) r = (x < y) +#define OP_FLOAT_GE(x,y,r) r = (x >= y) -#define OP_FLOAT_CMP(x,y,r,err) \ +#define OP_FLOAT_CMP(x,y,r) \ r = ((x > y) - (x < y)) /* addition, subtraction */ -#define OP_FLOAT_ADD(x,y,r,err) r = x + y -#define OP_FLOAT_SUB(x,y,r,err) r = x - y -#define OP_FLOAT_MUL(x,y,r,err) r = x * y -#define OP_FLOAT_DIV(x,y,r,err) r = x / y -#define OP_FLOAT_TRUEDIV(x,y,r,err) OP_FLOAT_DIV(x,y,r,err) -#define OP_FLOAT_POW(x,y,r,err) r = pow(x, y) +#define OP_FLOAT_ADD(x,y,r) r = x + y +#define OP_FLOAT_SUB(x,y,r) r = x - y +#define OP_FLOAT_MUL(x,y,r) r = x * y +#define OP_FLOAT_DIV(x,y,r) r = x / y +#define OP_FLOAT_TRUEDIV(x,y,r) OP_FLOAT_DIV(x,y,r) +#define OP_FLOAT_POW(x,y,r) r = pow(x, y) /*** conversions ***/ -#define OP_CAST_FLOAT_TO_INT(x,r,err) r = (long)(x) -#define OP_CAST_FLOAT_TO_UINT(x,r,err) r = (unsigned long)(x) -#define OP_CAST_INT_TO_FLOAT(x,r,err) r = (double)(x) -#define OP_CAST_UINT_TO_FLOAT(x,r,err) r = (double)(x) -#define OP_CAST_BOOL_TO_FLOAT(x,r,err) r = (double)(x) +#define OP_CAST_FLOAT_TO_INT(x,r) r = (long)(x) +#define OP_CAST_FLOAT_TO_UINT(x,r) r = (unsigned long)(x) +#define OP_CAST_INT_TO_FLOAT(x,r) r = (double)(x) +#define OP_CAST_UINT_TO_FLOAT(x,r) r = (double)(x) +#define OP_CAST_BOOL_TO_FLOAT(x,r) r = (double)(x) Modified: pypy/branch/explicit-exceptions/translator/c/src/int.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/int.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/int.h Fri Mar 24 23:08:22 2006 @@ -4,71 +4,71 @@ /*** unary operations ***/ -#define OP_INT_IS_TRUE(x,r,err) OP_INT_NE(x,0,r,err) +#define OP_INT_IS_TRUE(x,r) OP_INT_NE(x,0,r) -#define OP_INT_INVERT(x,r,err) r = ~((x)) +#define OP_INT_INVERT(x,r) r = ~((x)) -#define OP_INT_POS(x,r,err) r = x +#define OP_INT_POS(x,r) r = x -#define OP_INT_NEG(x,r,err) r = -(x) +#define OP_INT_NEG(x,r) r = -(x) -#define OP_INT_NEG_OVF(x,r,err) \ - OP_INT_NEG(x,r,err); \ +#define OP_INT_NEG_OVF(x,r) \ + OP_INT_NEG(x,r); \ if ((x) >= 0 || (x) != -(x)); \ - else FAIL_OVF(err, "integer negate") + else FAIL_OVF("integer negate") -#define OP_INT_ABS(x,r,err) r = (x) >= 0 ? x : -(x) -#define OP_UINT_ABS(x,r,err) r = (x) +#define OP_INT_ABS(x,r) r = (x) >= 0 ? x : -(x) +#define OP_UINT_ABS(x,r) r = (x) -#define OP_INT_ABS_OVF(x,r,err) \ - OP_INT_ABS(x,r,err); \ +#define OP_INT_ABS_OVF(x,r) \ + OP_INT_ABS(x,r); \ if ((x) >= 0 || (x) != -(x)); \ - else FAIL_OVF(err, "integer absolute") + else FAIL_OVF("integer absolute") /*** binary operations ***/ -#define OP_INT_EQ(x,y,r,err) r = ((x) == (y)) -#define OP_INT_NE(x,y,r,err) r = ((x) != (y)) -#define OP_INT_LE(x,y,r,err) r = ((x) <= (y)) -#define OP_INT_GT(x,y,r,err) r = ((x) > (y)) -#define OP_INT_LT(x,y,r,err) r = ((x) < (y)) -#define OP_INT_GE(x,y,r,err) r = ((x) >= (y)) +#define OP_INT_EQ(x,y,r) r = ((x) == (y)) +#define OP_INT_NE(x,y,r) r = ((x) != (y)) +#define OP_INT_LE(x,y,r) r = ((x) <= (y)) +#define OP_INT_GT(x,y,r) r = ((x) > (y)) +#define OP_INT_LT(x,y,r) r = ((x) < (y)) +#define OP_INT_GE(x,y,r) r = ((x) >= (y)) -#define OP_INT_CMP(x,y,r,err) \ +#define OP_INT_CMP(x,y,r) \ r = (((x) > (y)) - ((x) < (y))) /* addition, subtraction */ -#define OP_INT_ADD(x,y,r,err) r = (x) + (y) +#define OP_INT_ADD(x,y,r) r = (x) + (y) -#define OP_INT_ADD_OVF(x,y,r,err) \ - OP_INT_ADD(x,y,r,err); \ +#define OP_INT_ADD_OVF(x,y,r) \ + OP_INT_ADD(x,y,r); \ if ((r^(x)) >= 0 || (r^(y)) >= 0); \ - else FAIL_OVF(err, "integer addition") + else FAIL_OVF("integer addition") -#define OP_INT_SUB(x,y,r,err) r = (x) - (y) +#define OP_INT_SUB(x,y,r) r = (x) - (y) -#define OP_INT_SUB_OVF(x,y,r,err) \ - OP_INT_SUB(x,y,r,err); \ +#define OP_INT_SUB_OVF(x,y,r) \ + OP_INT_SUB(x,y,r); \ if ((r^(x)) >= 0 || (r^~(y)) >= 0); \ - else FAIL_OVF(err, "integer subtraction") + else FAIL_OVF("integer subtraction") -#define OP_INT_MUL(x,y,r,err) r = (x) * (y) +#define OP_INT_MUL(x,y,r) r = (x) * (y) #ifndef HAVE_LONG_LONG -#define OP_INT_MUL_OVF(x,y,r,err) \ +#define OP_INT_MUL_OVF(x,y,r) \ if (op_int_mul_ovf(x,y,&r)); \ - else FAIL_OVF(err, "integer multiplication") + else FAIL_OVF("integer multiplication") #else -#define OP_INT_MUL_OVF(x,y,r,err) \ +#define OP_INT_MUL_OVF(x,y,r) \ { \ PY_LONG_LONG lr = (PY_LONG_LONG)(x) * (PY_LONG_LONG)(y); \ r = (long)lr; \ if ((PY_LONG_LONG)r == lr); \ - else FAIL_OVF(err, "integer multiplication"); \ + else FAIL_OVF("integer multiplication"); \ } #endif @@ -76,99 +76,99 @@ /* NB. shifting has same limitations as C: the shift count must be >= 0 and < LONG_BITS. */ -#define OP_INT_RSHIFT(x,y,r,err) r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, y) -#define OP_UINT_RSHIFT(x,y,r,err) r = (x) >> (y) +#define OP_INT_RSHIFT(x,y,r) r = Py_ARITHMETIC_RIGHT_SHIFT(long, x, y) +#define OP_UINT_RSHIFT(x,y,r) r = (x) >> (y) -#define OP_INT_LSHIFT(x,y,r,err) r = (x) << (y) -#define OP_UINT_LSHIFT(x,y,r,err) r = (x) << (y) +#define OP_INT_LSHIFT(x,y,r) r = (x) << (y) +#define OP_UINT_LSHIFT(x,y,r) r = (x) << (y) -#define OP_INT_LSHIFT_OVF(x,y,r,err) \ - OP_INT_LSHIFT(x,y,r,err); \ +#define OP_INT_LSHIFT_OVF(x,y,r) \ + OP_INT_LSHIFT(x,y,r); \ if ((x) != Py_ARITHMETIC_RIGHT_SHIFT(long, r, (y))) \ - FAIL_OVF(err, "x<= 0) { OP_INT_RSHIFT(x,y,r,err); } \ - else FAIL_VAL(err, "negative shift count") - -#define OP_INT_LSHIFT_VAL(x,y,r,err) \ - if ((y) >= 0) { OP_INT_LSHIFT(x,y,r,err); } \ - else FAIL_VAL(err, "negative shift count") - -#define OP_INT_LSHIFT_OVF_VAL(x,y,r,err) \ - if ((y) >= 0) { OP_INT_LSHIFT_OVF(x,y,r,err); } \ - else FAIL_VAL(err, "negative shift count") +#define OP_INT_RSHIFT_VAL(x,y,r) \ + if ((y) >= 0) { OP_INT_RSHIFT(x,y,r); } \ + else FAIL_VAL("negative shift count") + +#define OP_INT_LSHIFT_VAL(x,y,r) \ + if ((y) >= 0) { OP_INT_LSHIFT(x,y,r); } \ + else FAIL_VAL("negative shift count") + +#define OP_INT_LSHIFT_OVF_VAL(x,y,r) \ + if ((y) >= 0) { OP_INT_LSHIFT_OVF(x,y,r); } \ + else FAIL_VAL("negative shift count") /* floor division */ -#define OP_INT_FLOORDIV(x,y,r,err) r = op_divmod_adj(x, y, NULL) -#define OP_UINT_FLOORDIV(x,y,r,err) r = (x) / (y) +#define OP_INT_FLOORDIV(x,y,r) r = op_divmod_adj(x, y, NULL) +#define OP_UINT_FLOORDIV(x,y,r) r = (x) / (y) -#define OP_INT_FLOORDIV_OVF(x,y,r,err) \ +#define OP_INT_FLOORDIV_OVF(x,y,r) \ if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \ - FAIL_OVF(err, "integer division"); \ - OP_INT_FLOORDIV(x,y,r,err) + { FAIL_OVF("integer division"); } \ + else OP_INT_FLOORDIV(x,y,r) -#define OP_INT_FLOORDIV_ZER(x,y,r,err) \ - if ((y)) { OP_INT_FLOORDIV(x,y,r,err); } \ - else FAIL_ZER(err, "integer division") -#define OP_UINT_FLOORDIV_ZER(x,y,r,err) \ - if ((y)) { OP_UINT_FLOORDIV(x,y,r,err); } \ - else FAIL_ZER(err, "unsigned integer division") - -#define OP_INT_FLOORDIV_OVF_ZER(x,y,r,err) \ - if ((y)) { OP_INT_FLOORDIV_OVF(x,y,r,err); } \ - else FAIL_ZER(err, "integer division") +#define OP_INT_FLOORDIV_ZER(x,y,r) \ + if ((y)) { OP_INT_FLOORDIV(x,y,r); } \ + else FAIL_ZER("integer division") +#define OP_UINT_FLOORDIV_ZER(x,y,r) \ + if ((y)) { OP_UINT_FLOORDIV(x,y,r); } \ + else FAIL_ZER("unsigned integer division") + +#define OP_INT_FLOORDIV_OVF_ZER(x,y,r) \ + if ((y)) { OP_INT_FLOORDIV_OVF(x,y,r); } \ + else FAIL_ZER("integer division") /* modulus */ -#define OP_INT_MOD(x,y,r,err) op_divmod_adj(x, y, &r) -#define OP_UINT_MOD(x,y,r,err) r = (x) % (y) +#define OP_INT_MOD(x,y,r) op_divmod_adj(x, y, &r) +#define OP_UINT_MOD(x,y,r) r = (x) % (y) -#define OP_INT_MOD_OVF(x,y,r,err) \ +#define OP_INT_MOD_OVF(x,y,r) \ if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \ - FAIL_OVF(err, "integer modulo"); \ - OP_INT_MOD(x,y,r,err) + { FAIL_OVF("integer modulo"); }\ + else OP_INT_MOD(x,y,r) -#define OP_INT_MOD_ZER(x,y,r,err) \ - if ((y)) { OP_INT_MOD(x,y,r,err); } \ - else FAIL_ZER(err, "integer modulo") -#define OP_UINT_MOD_ZER(x,y,r,err) \ - if ((y)) { OP_UINT_MOD(x,y,r,err); } \ - else FAIL_ZER(err, "unsigned integer modulo") - -#define OP_INT_MOD_OVF_ZER(x,y,r,err) \ - if ((y)) { OP_INT_MOD_OVF(x,y,r,err); } \ - else FAIL_ZER(err, "integer modulo") +#define OP_INT_MOD_ZER(x,y,r) \ + if ((y)) { OP_INT_MOD(x,y,r); } \ + else FAIL_ZER("integer modulo") +#define OP_UINT_MOD_ZER(x,y,r) \ + if ((y)) { OP_UINT_MOD(x,y,r); } \ + else FAIL_ZER("unsigned integer modulo") + +#define OP_INT_MOD_OVF_ZER(x,y,r) \ + if ((y)) { OP_INT_MOD_OVF(x,y,r); } \ + else FAIL_ZER("integer modulo") /* bit operations */ -#define OP_INT_AND(x,y,r,err) r = (x) & (y) -#define OP_INT_OR( x,y,r,err) r = (x) | (y) -#define OP_INT_XOR(x,y,r,err) r = (x) ^ (y) +#define OP_INT_AND(x,y,r) r = (x) & (y) +#define OP_INT_OR( x,y,r) r = (x) | (y) +#define OP_INT_XOR(x,y,r) r = (x) ^ (y) /*** conversions ***/ -#define OP_CAST_BOOL_TO_INT(x,r,err) r = (long)(x) -#define OP_CAST_BOOL_TO_UINT(x,r,err) r = (unsigned long)(x) -#define OP_CAST_UINT_TO_INT(x,r,err) r = (long)(x) -#define OP_CAST_INT_TO_UINT(x,r,err) r = (unsigned long)(x) -#define OP_CAST_INT_TO_LONGLONG(x,r,err) r = (long long)(x) -#define OP_CAST_CHAR_TO_INT(x,r,err) r = (long)((unsigned char)(x)) -#define OP_CAST_INT_TO_CHAR(x,r,err) r = (char)(x) -#define OP_CAST_PTR_TO_INT(x,r,err) r = (long)(x) /* XXX */ +#define OP_CAST_BOOL_TO_INT(x,r) r = (long)(x) +#define OP_CAST_BOOL_TO_UINT(x,r) r = (unsigned long)(x) +#define OP_CAST_UINT_TO_INT(x,r) r = (long)(x) +#define OP_CAST_INT_TO_UINT(x,r) r = (unsigned long)(x) +#define OP_CAST_INT_TO_LONGLONG(x,r) r = (long long)(x) +#define OP_CAST_CHAR_TO_INT(x,r) r = (long)((unsigned char)(x)) +#define OP_CAST_INT_TO_CHAR(x,r) r = (char)(x) +#define OP_CAST_PTR_TO_INT(x,r) r = (long)(x) /* XXX */ -#define OP_TRUNCATE_LONGLONG_TO_INT(x,r,err) r = (long)(x) +#define OP_TRUNCATE_LONGLONG_TO_INT(x,r) r = (long)(x) -#define OP_CAST_UNICHAR_TO_INT(x,r,err) r = (long)((unsigned long)(x)) /*?*/ -#define OP_CAST_INT_TO_UNICHAR(x,r,err) r = (unsigned int)(x) +#define OP_CAST_UNICHAR_TO_INT(x,r) r = (long)((unsigned long)(x)) /*?*/ +#define OP_CAST_INT_TO_UNICHAR(x,r) r = (unsigned int)(x) /* bool operations */ -#define OP_BOOL_NOT(x, r, err) r = !(x) +#define OP_BOOL_NOT(x, r) r = !(x) /* _________________ certain implementations __________________ */ Modified: pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h Fri Mar 24 23:08:22 2006 @@ -39,12 +39,11 @@ FAIL(exception_label); \ } #else -#define StacklessUnwindAndRPyExceptionHandling(unwind_label, resume_label, exception_label) \ +#define StacklessUnwindAndRPyExceptionHandling(unwind_label, resume_label) \ resume_label: \ if (RPyExceptionOccurred()) { \ if (slp_frame_stack_bottom) \ goto unwind_label; \ - FAIL(exception_label); \ } #endif @@ -54,12 +53,10 @@ #define RPyExceptionClear() -#define StacklessUnwindAndRPyExceptionHandling(unwind_label, resume_label, exception_label) do { \ +#define StacklessUnwindAndRPyExceptionHandling(unwind_label, resume_label) do { \ if (slp_frame_stack_bottom) \ goto unwind_label; \ resume_label: \ - if (RPyExceptionOccurred()) \ - FAIL(exception_label); \ } while (0) #endif Modified: pypy/branch/explicit-exceptions/translator/c/src/mem.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/mem.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/mem.h Fri Mar 24 23:08:22 2006 @@ -8,10 +8,10 @@ to compute the largest allowed number of items in the array. */ #define MAXIMUM_MALLOCABLE_SIZE (LONG_MAX-4096) -#define OP_MAX_VARSIZE(numitems, itemtype, err) { \ +#define OP_MAX_VARSIZE(numitems, itemtype) { \ if (((unsigned long)(numitems)) > \ (MAXIMUM_MALLOCABLE_SIZE / sizeof(itemtype))) \ - FAIL_EXCEPTION(err, PyExc_MemoryError, "addr space overflow"); \ + FAIL_EXCEPTION(PyExc_MemoryError, "addr space overflow"); \ } @@ -20,11 +20,13 @@ other globals, plus one. This upper bound "approximation" will do... */ #define REFCOUNT_IMMORTAL (INT_MAX/2) -#define OP_ZERO_MALLOC(size, r, err) { \ +#define OP_ZERO_MALLOC(size, r) { \ r = (void*) PyObject_Malloc(size); \ - if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ - memset((void*) r, 0, size); \ - COUNT_MALLOC; \ + if (r == NULL) {FAIL_EXCEPTION(PyExc_MemoryError, "out of memory"); } \ + else { \ + memset((void*) r, 0, size); \ + COUNT_MALLOC; \ + } \ } #define OP_FREE(p) { PyObject_Free(p); COUNT_FREE; } @@ -65,11 +67,13 @@ /* #define BOEHM_MALLOC_0_1 GC_MALLOC_IGNORE_OFF_PAGE */ /* #define BOEHM_MALLOC_1_1 GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE */ -#define OP_BOEHM_ZERO_MALLOC(size, r, is_atomic, is_varsize, err) { \ +#define OP_BOEHM_ZERO_MALLOC(size, r, is_atomic, is_varsize) { \ r = (void*) BOEHM_MALLOC_ ## is_atomic ## _ ## is_varsize (size); \ - if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory"); \ - if (is_atomic) /* the non-atomic versions return cleared memory */ \ - memset((void*) r, 0, size); \ + if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memoy"); \ + else { \ + if (is_atomic) /* the non-atomic versions return cleared memory */ \ + memset((void*) r, 0, size); \ + } \ } /* as we said in rbuiltin.py: @@ -77,7 +81,7 @@ # some kind of proper GC integration if GC integration has happened and this junk is still here, please delete it :) */ -#define OP_CALL_BOEHM_GC_ALLOC(size, r, err) OP_BOEHM_ZERO_MALLOC(size, r, 0, 0, err) +#define OP_CALL_BOEHM_GC_ALLOC(size, r) OP_BOEHM_ZERO_MALLOC(size, r, 0, 0) #endif /* USING_BOEHM_GC */ @@ -86,11 +90,13 @@ #undef OP_ZERO_MALLOC -#define OP_ZERO_MALLOC(size, r, err) { \ +#define OP_ZERO_MALLOC(size, r) { \ r = (void*) malloc(size); \ - if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");\ - memset((void*) r, 0, size); \ - COUNT_MALLOC; \ + if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memory");\ + else { \ + memset((void*) r, 0, size); \ + COUNT_MALLOC; \ + } \ } #undef PUSH_ALIVE Modified: pypy/branch/explicit-exceptions/translator/c/src/pyobj.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/pyobj.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/pyobj.h Fri Mar 24 23:08:22 2006 @@ -4,187 +4,198 @@ /*** as OP_XXX() macros calling the CPython API ***/ -#define op_bool(r,err,what) { \ +#define op_bool(r,what) { \ int _retval = what; \ - if (_retval < 0) CFAIL(err); \ - r = PyBool_FromLong(_retval); \ + if (_retval < 0) {CFAIL(); } \ + else \ + r = PyBool_FromLong(_retval); \ } -#define op_richcmp(x,y,r,err,dir) \ - if (!(r=PyObject_RichCompare(x,y,dir))) CFAIL(err) -#define OP_LT(x,y,r,err) op_richcmp(x,y,r,err, Py_LT) -#define OP_LE(x,y,r,err) op_richcmp(x,y,r,err, Py_LE) -#define OP_EQ(x,y,r,err) op_richcmp(x,y,r,err, Py_EQ) -#define OP_NE(x,y,r,err) op_richcmp(x,y,r,err, Py_NE) -#define OP_GT(x,y,r,err) op_richcmp(x,y,r,err, Py_GT) -#define OP_GE(x,y,r,err) op_richcmp(x,y,r,err, Py_GE) - -#define OP_IS_(x,y,r,err) op_bool(r,err,(x == y)) - -#define OP_IS_TRUE(x,r,err) op_bool(r,err,PyObject_IsTrue(x)) -#define OP_NONZERO(x,r,err) op_bool(r,err,PyObject_IsTrue(x)) - -#define OP_LEN(x,r,err) { \ - int _retval = PyObject_Size(x); \ - if (_retval < 0) CFAIL(err); \ - r = PyInt_FromLong(_retval); \ +#define op_richcmp(x,y,r,dir) \ + if (!(r=PyObject_RichCompare(x,y,dir))) CFAIL() +#define OP_LT(x,y,r) op_richcmp(x,y,r, Py_LT) +#define OP_LE(x,y,r) op_richcmp(x,y,r, Py_LE) +#define OP_EQ(x,y,r) op_richcmp(x,y,r, Py_EQ) +#define OP_NE(x,y,r) op_richcmp(x,y,r, Py_NE) +#define OP_GT(x,y,r) op_richcmp(x,y,r, Py_GT) +#define OP_GE(x,y,r) op_richcmp(x,y,r, Py_GE) + +#define OP_IS_(x,y,r) op_bool(r,(x == y)) + +#define OP_IS_TRUE(x,r) op_bool(r,PyObject_IsTrue(x)) +#define OP_NONZERO(x,r) op_bool(r,PyObject_IsTrue(x)) + +#define OP_LEN(x,r) { \ + int _retval = PyObject_Size(x); \ + if (_retval < 0) { CFAIL() }; \ + else \ + r = PyInt_FromLong(_retval); \ } -#define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) CFAIL(err) -#define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) CFAIL(err) -#define OP_INVERT(x,r,err) if (!(r=PyNumber_Invert(x))) CFAIL(err) -#define OP_ABS(x,r,err) if (!(r=PyNumber_Absolute(x))) CFAIL(err) - -#define OP_ADD(x,y,r,err) if (!(r=PyNumber_Add(x,y))) CFAIL(err) -#define OP_SUB(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) CFAIL(err) -#define OP_MUL(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) CFAIL(err) -#define OP_TRUEDIV(x,y,r,err) if (!(r=PyNumber_TrueDivide(x,y))) CFAIL(err) -#define OP_FLOORDIV(x,y,r,err) if (!(r=PyNumber_FloorDivide(x,y)))CFAIL(err) -#define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) CFAIL(err) -#define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) CFAIL(err) -#define OP_DIVMOD(x,y,r,err) if (!(r=PyNumber_Divmod(x,y))) CFAIL(err) -#define OP_POW(x,y,z,r,err) if (!(r=PyNumber_Power(x,y,z))) CFAIL(err) -#define OP_LSHIFT(x,y,r,err) if (!(r=PyNumber_Lshift(x,y))) CFAIL(err) -#define OP_RSHIFT(x,y,r,err) if (!(r=PyNumber_Rshift(x,y))) CFAIL(err) -#define OP_AND_(x,y,r,err) if (!(r=PyNumber_And(x,y))) CFAIL(err) -#define OP_OR_(x,y,r,err) if (!(r=PyNumber_Or(x,y))) CFAIL(err) -#define OP_XOR(x,y,r,err) if (!(r=PyNumber_Xor(x,y))) CFAIL(err) - -#define OP_INPLACE_ADD(x,y,r,err) if (!(r=PyNumber_InPlaceAdd(x,y))) \ - CFAIL(err) -#define OP_INPLACE_SUB(x,y,r,err) if (!(r=PyNumber_InPlaceSubtract(x,y))) \ - CFAIL(err) -#define OP_INPLACE_MUL(x,y,r,err) if (!(r=PyNumber_InPlaceMultiply(x,y))) \ - CFAIL(err) -#define OP_INPLACE_TRUEDIV(x,y,r,err) if (!(r=PyNumber_InPlaceTrueDivide(x,y)))\ - CFAIL(err) -#define OP_INPLACE_FLOORDIV(x,y,r,err)if(!(r=PyNumber_InPlaceFloorDivide(x,y)))\ - CFAIL(err) -#define OP_INPLACE_DIV(x,y,r,err) if (!(r=PyNumber_InPlaceDivide(x,y))) \ - CFAIL(err) -#define OP_INPLACE_MOD(x,y,r,err) if (!(r=PyNumber_InPlaceRemainder(x,y))) \ - CFAIL(err) -#define OP_INPLACE_POW(x,y,r,err) if (!(r=PyNumber_InPlacePower(x,y,Py_None))) \ - CFAIL(err) -#define OP_INPLACE_LSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceLshift(x,y))) \ - CFAIL(err) -#define OP_INPLACE_RSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceRshift(x,y))) \ - CFAIL(err) -#define OP_INPLACE_AND(x,y,r,err) if (!(r=PyNumber_InPlaceAnd(x,y))) \ - CFAIL(err) -#define OP_INPLACE_OR(x,y,r,err) if (!(r=PyNumber_InPlaceOr(x,y))) \ - CFAIL(err) -#define OP_INPLACE_XOR(x,y,r,err) if (!(r=PyNumber_InPlaceXor(x,y))) \ - CFAIL(err) - -#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) CFAIL(err) -#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) CFAIL(err);\ +#define OP_NEG(x,r) if (!(r=PyNumber_Negative(x))) CFAIL() +#define OP_POS(x,r) if (!(r=PyNumber_Positive(x))) CFAIL() +#define OP_INVERT(x,r) if (!(r=PyNumber_Invert(x))) CFAIL() +#define OP_ABS(x,r) if (!(r=PyNumber_Absolute(x))) CFAIL() + +#define OP_ADD(x,y,r) if (!(r=PyNumber_Add(x,y))) CFAIL() +#define OP_SUB(x,y,r) if (!(r=PyNumber_Subtract(x,y))) CFAIL() +#define OP_MUL(x,y,r) if (!(r=PyNumber_Multiply(x,y))) CFAIL() +#define OP_TRUEDIV(x,y,r) if (!(r=PyNumber_TrueDivide(x,y))) CFAIL() +#define OP_FLOORDIV(x,y,r) if (!(r=PyNumber_FloorDivide(x,y)))CFAIL() +#define OP_DIV(x,y,r) if (!(r=PyNumber_Divide(x,y))) CFAIL() +#define OP_MOD(x,y,r) if (!(r=PyNumber_Remainder(x,y))) CFAIL() +#define OP_DIVMOD(x,y,r) if (!(r=PyNumber_Divmod(x,y))) CFAIL() +#define OP_POW(x,y,z,r) if (!(r=PyNumber_Power(x,y,z))) CFAIL() +#define OP_LSHIFT(x,y,r) if (!(r=PyNumber_Lshift(x,y))) CFAIL() +#define OP_RSHIFT(x,y,r) if (!(r=PyNumber_Rshift(x,y))) CFAIL() +#define OP_AND_(x,y,r) if (!(r=PyNumber_And(x,y))) CFAIL() +#define OP_OR_(x,y,r) if (!(r=PyNumber_Or(x,y))) CFAIL() +#define OP_XOR(x,y,r) if (!(r=PyNumber_Xor(x,y))) CFAIL() + +#define OP_INPLACE_ADD(x,y,r) if (!(r=PyNumber_InPlaceAdd(x,y))) \ + CFAIL() +#define OP_INPLACE_SUB(x,y,r) if (!(r=PyNumber_InPlaceSubtract(x,y))) \ + CFAIL() +#define OP_INPLACE_MUL(x,y,r) if (!(r=PyNumber_InPlaceMultiply(x,y))) \ + CFAIL() +#define OP_INPLACE_TRUEDIV(x,y,r) if (!(r=PyNumber_InPlaceTrueDivide(x,y)))\ + CFAIL() +#define OP_INPLACE_FLOORDIV(x,y,r)if(!(r=PyNumber_InPlaceFloorDivide(x,y)))\ + CFAIL() +#define OP_INPLACE_DIV(x,y,r) if (!(r=PyNumber_InPlaceDivide(x,y))) \ + CFAIL() +#define OP_INPLACE_MOD(x,y,r) if (!(r=PyNumber_InPlaceRemainder(x,y))) \ + CFAIL() +#define OP_INPLACE_POW(x,y,r) if (!(r=PyNumber_InPlacePower(x,y,Py_None))) \ + CFAIL() +#define OP_INPLACE_LSHIFT(x,y,r) if (!(r=PyNumber_InPlaceLshift(x,y))) \ + CFAIL() +#define OP_INPLACE_RSHIFT(x,y,r) if (!(r=PyNumber_InPlaceRshift(x,y))) \ + CFAIL() +#define OP_INPLACE_AND(x,y,r) if (!(r=PyNumber_InPlaceAnd(x,y))) \ + CFAIL() +#define OP_INPLACE_OR(x,y,r) if (!(r=PyNumber_InPlaceOr(x,y))) \ + CFAIL() +#define OP_INPLACE_XOR(x,y,r) if (!(r=PyNumber_InPlaceXor(x,y))) \ + CFAIL() + +#define OP_GETITEM(x,y,r) if (!(r=PyObject_GetItem1(x,y))) CFAIL() +#define OP_SETITEM(x,y,z,r) if ((PyObject_SetItem1(x,y,z))<0) {CFAIL(); }\ + else \ r=Py_None; Py_INCREF(r) -#define OP_DELITEM(x,y,r,err) if ((PyObject_DelItem(x,y))<0) CFAIL(err);\ +#define OP_DELITEM(x,y,r) if ((PyObject_DelItem(x,y))<0) CFAIL();\ r=Py_None; Py_INCREF(r) -#define OP_CONTAINS(x,y,r,err) op_bool(r,err,(PySequence_Contains(x,y))) +#define OP_CONTAINS(x,y,r) op_bool(r,(PySequence_Contains(x,y))) -#define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) CFAIL(err) -#define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) CFAIL(err);\ +#define OP_GETATTR(x,y,r) if (!(r=PyObject_GetAttr(x,y))) CFAIL() +#define OP_SETATTR(x,y,z,r) if ((PyObject_SetAttr(x,y,z))<0) {CFAIL();}\ + else \ r=Py_None; Py_INCREF(r) -#define OP_DELATTR(x,y,r,err) if ((PyObject_SetAttr(x,y,NULL))<0)CFAIL(err);\ +#define OP_DELATTR(x,y,r) if ((PyObject_SetAttr(x,y,NULL))<0) {CFAIL();}\ + else \ r=Py_None; Py_INCREF(r) -#define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) CFAIL(err) +#define OP_NEWSLICE(x,y,z,r) if (!(r=PySlice_New(x,y,z))) CFAIL() -#define OP_GETSLICE(x,y,z,r,err) { \ +#define OP_GETSLICE(x,y,z,r) { \ PyObject *__yo = y, *__zo = z; \ int __y = 0, __z = INT_MAX; \ if (__yo == Py_None) __yo = NULL; \ if (__zo == Py_None) __zo = NULL; \ if (!_PyEval_SliceIndex(__yo, &__y) || \ !_PyEval_SliceIndex(__zo, &__z) || \ - !(r=PySequence_GetSlice(x, __y, __z))) CFAIL(err); \ + !(r=PySequence_GetSlice(x, __y, __z))) CFAIL(); \ } -#define OP_ALLOC_AND_SET(x,y,r,err) { \ +#define OP_ALLOC_AND_SET(x,y,r) { \ /* XXX check for long/int overflow */ \ int __i, __x = PyInt_AsLong(x); \ - if (PyErr_Occurred()) CFAIL(err); \ - if (!(r = PyList_New(__x))) CFAIL(err); \ - for (__i=0; __i<__x; __i++) { \ - Py_INCREF(y); \ - PyList_SET_ITEM(r, __i, y); \ - } \ + if (PyErr_Occurred()) CFAIL(); \ + else { \ + if (!(r = PyList_New(__x))) CFAIL(); \ + else { \ + for (__i=0; __i<__x; __i++) { \ + Py_INCREF(y); \ + PyList_SET_ITEM(r, __i, y); \ + } \ + } \ + } \ } -#define OP_ITER(x,r,err) if (!(r=PyObject_GetIter(x))) CFAIL(err) -#define OP_NEXT(x,r,err) if (!(r=PyIter_Next(x))) { \ +#define OP_ITER(x,r) if (!(r=PyObject_GetIter(x))) CFAIL() +#define OP_NEXT(x,r) if (!(r=PyIter_Next(x))) { \ if (!PyErr_Occurred()) PyErr_SetNone(PyExc_StopIteration); \ - CFAIL(err); \ + CFAIL(); \ } -#define OP_STR(x,r,err) if (!(r=PyObject_Str(x))) CFAIL(err) -#define OP_REPR(x,r,err) if (!(r=PyObject_Repr(x))) CFAIL(err) -#define OP_ORD(s,r,err) { \ +#define OP_STR(x,r) if (!(r=PyObject_Str(x))) CFAIL() +#define OP_REPR(x,r) if (!(r=PyObject_Repr(x))) CFAIL() +#define OP_ORD(s,r) { \ char *__c = PyString_AsString(s); \ int __len; \ - if ( !__c) CFAIL(err); \ - if ((__len = PyString_GET_SIZE(s)) != 1) { \ - PyErr_Format(PyExc_TypeError, \ - "ord() expected a character, but string of length %d found", \ - __len); \ - CFAIL(err); \ - } \ - if (!(r = PyInt_FromLong((unsigned char)(__c[0])))) \ - CFAIL(err); \ + if ( !__c) CFAIL(); \ + else { \ + if ((__len = PyString_GET_SIZE(s)) != 1) { \ + PyErr_Format(PyExc_TypeError, \ + "ord() expected a character, but string of length %d found", \ + __len); \ + CFAIL(); \ + } \ + else if (!(r = PyInt_FromLong((unsigned char)(__c[0])))) \ + { CFAIL(); }\ + } \ } -#define OP_ID(x,r,err) if (!(r=PyLong_FromVoidPtr(x))) CFAIL(err) -#define OP_HASH(x,r,err) { \ +#define OP_ID(x,r) if (!(r=PyLong_FromVoidPtr(x))) CFAIL() +#define OP_HASH(x,r) { \ long __hash = PyObject_Hash(x); \ - if (__hash == -1 && PyErr_Occurred()) CFAIL(err); \ - if (!(r = PyInt_FromLong(__hash))) CFAIL(err); \ + if (__hash == -1 && PyErr_Occurred()) CFAIL(); \ + else if (!(r = PyInt_FromLong(__hash))) { CFAIL(); } \ } -#define OP_HEX(x,r,err) { \ +#define OP_HEX(x,r) { \ PyNumberMethods *__nb; \ if ((__nb = x->ob_type->tp_as_number) == NULL || \ __nb->nb_hex == NULL) { \ PyErr_SetString(PyExc_TypeError, \ "hex() argument can't be converted to hex"); \ - CFAIL(err); \ + CFAIL(); \ } \ - if (!(r = (*__nb->nb_hex)(x))) CFAIL(err); \ + else if (!(r = (*__nb->nb_hex)(x))) { CFAIL(); } \ } -#define OP_OCT(x,r,err) { \ +#define OP_OCT(x,r) { \ PyNumberMethods *__nb; \ if ((__nb = x->ob_type->tp_as_number) == NULL || \ __nb->nb_oct == NULL) { \ PyErr_SetString(PyExc_TypeError, \ "oct() argument can't be converted to oct"); \ - CFAIL(err); \ + CFAIL(); \ } \ - if (!(r = (*__nb->nb_oct)(x))) CFAIL(err); \ + else if (!(r = (*__nb->nb_oct)(x))) { CFAIL(); } \ } -#define OP_INT(x,r,err) { \ +#define OP_INT(x,r) { \ long __val = PyInt_AsLong(x); \ - if (__val == -1 && PyErr_Occurred()) CFAIL(err); \ - if (!(r = PyInt_FromLong(__val))) CFAIL (err); \ + if (__val == -1 && PyErr_Occurred()) CFAIL(); \ + else if (!(r = PyInt_FromLong(__val))) { CFAIL (); } \ } -#define OP_FLOAT(x,r,err) { \ +#define OP_FLOAT(x,r) { \ double __val = PyFloat_AsDouble(x); \ - if (PyErr_Occurred()) CFAIL(err); \ - if (!(r = PyFloat_FromDouble(__val))) CFAIL (err); \ + if (PyErr_Occurred()) CFAIL(); \ + else if (!(r = PyFloat_FromDouble(__val))) { CFAIL (); } \ } -#define OP_CMP(x,y,r,err) { \ +#define OP_CMP(x,y,r) { \ int __val = PyObject_Compare(x, y); \ - if (PyErr_Occurred()) CFAIL(err); \ - if (!(r = PyInt_FromLong(__val))) CFAIL (err); \ + if (PyErr_Occurred()) CFAIL(); \ + else if (!(r = PyInt_FromLong(__val))) { CFAIL (); }\ } -#define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ - CFAIL(err) -#define OP_CALL_ARGS(args,r,err) if (!(r=CallWithShape args)) CFAIL(err) +#define OP_SIMPLE_CALL(args,r) if (!(r=PyObject_CallFunctionObjArgs args)) \ + CFAIL() +#define OP_CALL_ARGS(args,r) if (!(r=CallWithShape args)) CFAIL() /* Needs to act like getattr(x, '__class__', type(x)) */ -#define OP_TYPE(x,r,err) { \ +#define OP_TYPE(x,r) { \ PyObject *o = x; \ if (PyInstance_Check(o)) { \ r = (PyObject*)(((PyInstanceObject*)o)->in_class); \ @@ -195,26 +206,26 @@ } /* Needs to act like instance(x,y) */ -#define OP_ISSUBTYPE(x,y,r,err) \ - op_bool(r,err,PyObject_IsSubclass(x, y)) +#define OP_ISSUBTYPE(x,y,r) \ + op_bool(r,PyObject_IsSubclass(x, y)) /*** operations with a variable number of arguments ***/ -#define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) CFAIL(err) -#define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) CFAIL(err) -#define OP_NEWDICT0(r,err) if (!(r=PyDict_New())) CFAIL(err) -#define OP_NEWDICT(args,r,err) if (!(r=PyDict_Pack args)) CFAIL(err) -#define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) CFAIL(err) +#define OP_NEWLIST0(r) if (!(r=PyList_New(0))) CFAIL() +#define OP_NEWLIST(args,r) if (!(r=PyList_Pack args)) CFAIL() +#define OP_NEWDICT0(r) if (!(r=PyDict_New())) CFAIL() +#define OP_NEWDICT(args,r) if (!(r=PyDict_Pack args)) CFAIL() +#define OP_NEWTUPLE(args,r) if (!(r=PyTuple_Pack args)) CFAIL() /*** argument parsing ***/ -#define OP_DECODE_ARG(fname, pos, name, vargs, vkwds, r, err) \ - if (!(r=decode_arg(fname, pos, name, vargs, vkwds, NULL))) CFAIL(err) -#define OP_DECODE_ARG_DEF(fname, pos, name, vargs, vkwds, def, r, err) \ - if (!(r=decode_arg(fname, pos, name, vargs, vkwds, def))) CFAIL(err) -#define OP_CHECK_NO_MORE_ARG(fname, n, vargs, r, err) \ - if (check_no_more_arg(fname, n, vargs) < 0) CFAIL(err) +#define OP_DECODE_ARG(fname, pos, name, vargs, vkwds, r) \ + if (!(r=decode_arg(fname, pos, name, vargs, vkwds, NULL))) CFAIL() +#define OP_DECODE_ARG_DEF(fname, pos, name, vargs, vkwds, def, r) \ + if (!(r=decode_arg(fname, pos, name, vargs, vkwds, def))) CFAIL() +#define OP_CHECK_NO_MORE_ARG(fname, n, vargs, r) \ + if (check_no_more_arg(fname, n, vargs) < 0) CFAIL() unsigned long long RPyLong_AsUnsignedLongLong(PyObject *v); long long RPyLong_AsLongLong(PyObject *v); Modified: pypy/branch/explicit-exceptions/translator/c/src/support.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/support.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/support.h Fri Mar 24 23:08:22 2006 @@ -9,15 +9,14 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ -#define FAIL_EXCEPTION(err, exc, msg) \ +#define FAIL_EXCEPTION(exc, msg) \ { \ RPyRaiseSimpleException(exc, msg); \ - FAIL(err); \ } -#define FAIL_OVF(err, msg) FAIL_EXCEPTION(err, PyExc_OverflowError, msg) -#define FAIL_VAL(err, msg) FAIL_EXCEPTION(err, PyExc_ValueError, msg) -#define FAIL_ZER(err, msg) FAIL_EXCEPTION(err, PyExc_ZeroDivisionError, msg) -#define CFAIL(err) { RPyConvertExceptionFromCPython(); FAIL(err); } +#define FAIL_OVF(msg) FAIL_EXCEPTION(PyExc_OverflowError, msg) +#define FAIL_VAL(msg) FAIL_EXCEPTION(PyExc_ValueError, msg) +#define FAIL_ZER(msg) FAIL_EXCEPTION(PyExc_ZeroDivisionError, msg) +#define CFAIL() { RPyConvertExceptionFromCPython(); } #define PyString_FromLLCharArrayAndSize(itemsarray, size) \ PyString_FromStringAndSize(itemsarray->items, size) Modified: pypy/branch/explicit-exceptions/translator/c/src/trace.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/trace.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/trace.h Fri Mar 24 23:08:22 2006 @@ -16,8 +16,6 @@ #define TRACE_CALL __f, __tstate #define TRACE_ARGS PyFrameObject *__f, PyThreadState *__tstate -#define FAIL(err) { __f->f_lineno = __f->f_code->co_firstlineno = __LINE__; goto err; } - #define FUNCTION_HEAD(signature, self, args, names, file, line) \ PyThreadState *__tstate = PyThreadState_GET(); \ PyObject *__localnames = PyList_CrazyStringPack names; \ @@ -32,10 +30,6 @@ #else /* !defined(USE_CALL_TRACE) */ -/* XXX we need to be more clever when exception handling actually checks for - * specific error values */ -#define FAIL(err) /*goto err */ - #endif /* defined(USE_CALL_TRACE) */ Modified: pypy/branch/explicit-exceptions/translator/c/src/unichar.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/unichar.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/unichar.h Fri Mar 24 23:08:22 2006 @@ -6,6 +6,6 @@ /*** binary operations ***/ /* typedef unsigned pypy_unichar; */ -#define OP_UNICHAR_EQ(x,y,r,err) r = ((x) == (y)) -#define OP_UNICHAR_NE(x,y,r,err) r = ((x) != (y)) +#define OP_UNICHAR_EQ(x,y,r) r = ((x) == (y)) +#define OP_UNICHAR_NE(x,y,r) r = ((x) != (y)) Modified: pypy/branch/explicit-exceptions/translator/c/stackless.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/stackless.py (original) +++ pypy/branch/explicit-exceptions/translator/c/stackless.py Fri Mar 24 23:08:22 2006 @@ -257,7 +257,7 @@ del self.savelines del self.resumeblocks - def check_directcall_result(self, op, err, specialreturnvalue=None): + def check_directcall_result(self, op, specialreturnvalue=None): slp = self.db.stacklessdata # don't generate code for calls that cannot unwind if not specialreturnvalue: @@ -272,7 +272,7 @@ if not need_stackless: slp.count_calls[False] += 1 return (super(SlpFunctionCodeGenerator, self) - .check_directcall_result(op, err)) + .check_directcall_result(op)) slp.count_calls[True] += 1 block = self.currentblock curpos = block.operations.index(op) @@ -336,16 +336,16 @@ # add the checks for the unwinding case just after the directcall # in the source return 'StacklessUnwindAndRPyExceptionHandling(%s,%s,%s);' % ( - savelabel, resumelabel, err) + savelabel, resumelabel) - def OP_YIELD_CURRENT_FRAME_TO_CALLER(self, op, err): + def OP_YIELD_CURRENT_FRAME_TO_CALLER(self, op): # special handling of this operation: call stack_unwind() to force the # current frame to be saved into the heap, but don't propagate the # unwind -- instead, capture it and return it normally line = '/* yield_current_frame_to_caller */\n' line += '%s = NULL;\n' % self.expr(op.result) line += 'LL_stackless_stack_unwind();\n' - line += self.check_directcall_result(op, err, + line += self.check_directcall_result(op, specialreturnvalue='slp_return_current_frame_to_caller()') return line From pedronis at codespeak.net Sat Mar 25 00:07:27 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Mar 2006 00:07:27 +0100 (CET) Subject: [pypy-svn] r24984 - in pypy/dist/pypy: rpython/memory translator/c Message-ID: <20060324230727.642371012D@code0.codespeak.net> Author: pedronis Date: Sat Mar 25 00:07:20 2006 New Revision: 24984 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/funcgen.py Log: try to fix gctransform and PyObject interaction (at least for refcounting). Hackish/quick way. This needs to be done properly on the branch. test_refcount_pyobj passes. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 25 00:07:20 2006 @@ -273,7 +273,11 @@ def pop_alive_nopyobj(self, var): return [] - + def replace_getfield(self, op, livevars, block): # XXX hackish solution for now + getvalop = SpaceOperation("bare_getfield", + [op.args[0], op.args[1]], op.result) + return [getvalop], [] + # ---------------------------------------------------------------- def _static_deallocator_body_for_type(v, TYPE, depth=1): @@ -394,11 +398,15 @@ if not var_needsgc(op.args[2]): return [op], [] oldval = varoftype(op.args[2].concretetype) - getoldvalop = SpaceOperation("getfield", + getoldvalop = SpaceOperation("bare_getfield", [op.args[0], op.args[1]], oldval) result = [getoldvalop] result.extend(self.push_alive(op.args[2])) - result.append(op) + setvalop = SpaceOperation("bare_setfield", + op.args, op.result) + + + result.append(setvalop) return result, self.pop_alive(oldval) def replace_setarrayitem(self, op, livevars, block): @@ -505,10 +513,10 @@ g, fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void) # the produced deallocator graph does not need to be transformed self.seen_graphs[g] = True - if destrptr: - # however, the direct_call to the destructor needs to get - # .cleanup attached - self.deallocator_graphs_needing_transforming.append(g) + #if destrptr: + # however, the direct_call to the destructor needs to get + # .cleanup attached + self.deallocator_graphs_needing_transforming.append(g) self.static_deallocator_funcptrs[TYPE] = fptr for p in find_gc_ptrs_in_type(TYPE): Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Sat Mar 25 00:07:20 2006 @@ -12,7 +12,7 @@ LOCALVAR = 'l_%s' # I'm not absolutely sure, so just in case: -NEED_OLD_EXTRA_REFS = False +NEED_OLD_EXTRA_REFS = True # we need them for now, should go in the tranformation! class FunctionCodeGenerator(object): """ @@ -453,11 +453,12 @@ return 'if (RPyExceptionOccurred())\n\tFAIL(%s);' % err # low-level operations - def generic_get(self, op, sourceexpr): + def generic_get(self, op, sourceexpr, bare=False): T = self.lltypemap(op.result) newvalue = self.expr(op.result, special_case_void=False) result = ['%s = %s;' % (newvalue, sourceexpr)] # need to adjust the refcount of the result only for PyObjects + print "BARE", bare if NEED_OLD_EXTRA_REFS and T == PyObjPtr: result.append('Py_XINCREF(%s);' % newvalue) result = '\n'.join(result) @@ -474,14 +475,17 @@ result = '/* %s */' % result return result - def OP_GETFIELD(self, op, err, ampersand=''): + def OP_GETFIELD(self, op, err, ampersand='', bare=False): assert isinstance(op.args[1], Constant) STRUCT = self.lltypemap(op.args[0]).TO structdef = self.db.gettypedefnode(STRUCT) fieldname = structdef.c_struct_field_name(op.args[1].value) return self.generic_get(op, '%s%s->%s' % (ampersand, self.expr(op.args[0]), - fieldname)) + fieldname), bare=bare) + + def OP_BARE_GETFIELD(self, op, err, ampersand=''): + return self.OP_GETFIELD(op, err, ampersand, bare=True) def OP_SETFIELD(self, op, err): assert isinstance(op.args[1], Constant) @@ -491,6 +495,8 @@ return self.generic_set(op, '%s->%s' % (self.expr(op.args[0]), fieldname)) + OP_BARE_SETFIELD = OP_SETFIELD + def OP_GETSUBSTRUCT(self, op, err): return self.OP_GETFIELD(op, err, ampersand='&') From cfbolz at codespeak.net Sat Mar 25 00:30:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 25 Mar 2006 00:30:10 +0100 (CET) Subject: [pypy-svn] r24985 - pypy/branch/explicit-exceptions/translator/c/src Message-ID: <20060324233010.1545710137@code0.codespeak.net> Author: cfbolz Date: Sat Mar 25 00:29:59 2006 New Revision: 24985 Modified: pypy/branch/explicit-exceptions/translator/c/src/mem.h Log: ouch. it is not a good idea to forget the braces there Modified: pypy/branch/explicit-exceptions/translator/c/src/mem.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/mem.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/mem.h Sat Mar 25 00:29:59 2006 @@ -69,7 +69,7 @@ #define OP_BOEHM_ZERO_MALLOC(size, r, is_atomic, is_varsize) { \ r = (void*) BOEHM_MALLOC_ ## is_atomic ## _ ## is_varsize (size); \ - if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memoy"); \ + if (r == NULL) {FAIL_EXCEPTION(PyExc_MemoryError, "out of memoy");} \ else { \ if (is_atomic) /* the non-atomic versions return cleared memory */ \ memset((void*) r, 0, size); \ @@ -92,7 +92,7 @@ #define OP_ZERO_MALLOC(size, r) { \ r = (void*) malloc(size); \ - if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memory");\ + if (r == NULL) { FAIL_EXCEPTION(PyExc_MemoryError, "out of memory"); } \ else { \ memset((void*) r, 0, size); \ COUNT_MALLOC; \ From arigo at codespeak.net Sat Mar 25 00:32:11 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Mar 2006 00:32:11 +0100 (CET) Subject: [pypy-svn] r24986 - pypy/dist/pypy/rpython/memory/test Message-ID: <20060324233211.E950E10141@code0.codespeak.net> Author: arigo Date: Sat Mar 25 00:32:09 2006 New Revision: 24986 Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py Log: A guess at the intended meaning of these lines. Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gc.py Sat Mar 25 00:32:09 2006 @@ -38,8 +38,8 @@ class TestMarkSweepGC(object): def setup_class(cls): cls.prep_old = gclltype.prepare_graphs_and_create_gc - gclltype.use_gc = MarkSweepGC cls.old = gclltype.use_gc + gclltype.use_gc = MarkSweepGC def teardown_class(cls): gclltype.prepare_graphs_and_create_gc = cls.prep_old.im_func From pedronis at codespeak.net Sat Mar 25 00:39:49 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Mar 2006 00:39:49 +0100 (CET) Subject: [pypy-svn] r24987 - in pypy/dist/pypy: rpython/memory translator/c Message-ID: <20060324233949.0B7981014D@code0.codespeak.net> Author: pedronis Date: Sat Mar 25 00:39:47 2006 New Revision: 24987 Modified: pypy/dist/pypy/rpython/memory/gctransform.py pypy/dist/pypy/translator/c/funcgen.py Log: oops. this was the real intention. Modified: pypy/dist/pypy/rpython/memory/gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform.py Sat Mar 25 00:39:47 2006 @@ -267,10 +267,10 @@ return c class MinimalGCTransformer(GCTransformer): - def push_alive_nopyobj(self, var): + def push_alive(self, var): return [] - def pop_alive_nopyobj(self, var): + def pop_alive(self, var): return [] def replace_getfield(self, op, livevars, block): # XXX hackish solution for now Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Sat Mar 25 00:39:47 2006 @@ -458,8 +458,7 @@ newvalue = self.expr(op.result, special_case_void=False) result = ['%s = %s;' % (newvalue, sourceexpr)] # need to adjust the refcount of the result only for PyObjects - print "BARE", bare - if NEED_OLD_EXTRA_REFS and T == PyObjPtr: + if not bare and NEED_OLD_EXTRA_REFS and T == PyObjPtr: result.append('Py_XINCREF(%s);' % newvalue) result = '\n'.join(result) if T is Void: From cfbolz at codespeak.net Sat Mar 25 01:14:42 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 25 Mar 2006 01:14:42 +0100 (CET) Subject: [pypy-svn] r24988 - in pypy/branch/explicit-exceptions/translator/c: . src Message-ID: <20060325001442.3A8C71014D@code0.codespeak.net> Author: cfbolz Date: Sat Mar 25 01:14:39 2006 New Revision: 24988 Modified: pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h pypy/branch/explicit-exceptions/translator/c/stackless.py Log: fix stackless typos introduced by the big macro rewrite Modified: pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h (original) +++ pypy/branch/explicit-exceptions/translator/c/src/ll_stackless.h Sat Mar 25 01:14:39 2006 @@ -57,6 +57,7 @@ if (slp_frame_stack_bottom) \ goto unwind_label; \ resume_label: \ + ; \ } while (0) #endif Modified: pypy/branch/explicit-exceptions/translator/c/stackless.py ============================================================================== --- pypy/branch/explicit-exceptions/translator/c/stackless.py (original) +++ pypy/branch/explicit-exceptions/translator/c/stackless.py Sat Mar 25 01:14:39 2006 @@ -335,7 +335,7 @@ # add the checks for the unwinding case just after the directcall # in the source - return 'StacklessUnwindAndRPyExceptionHandling(%s,%s,%s);' % ( + return 'StacklessUnwindAndRPyExceptionHandling(%s,%s);' % ( savelabel, resumelabel) def OP_YIELD_CURRENT_FRAME_TO_CALLER(self, op): From tismer at codespeak.net Sat Mar 25 08:25:12 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 25 Mar 2006 08:25:12 +0100 (CET) Subject: [pypy-svn] r24990 - in pypy/dist/pypy/translator/c: . test Message-ID: <20060325072512.8D6C71011A@code0.codespeak.net> Author: tismer Date: Sat Mar 25 08:25:03 2006 New Revision: 24990 Modified: pypy/dist/pypy/translator/c/database.py pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/pyobj.py pypy/dist/pypy/translator/c/test/test_wrapping.py Log: finally after lots of tiny hassles, here is a working implementation of a generated extension module that exposes its classes and can really be used. sigh :=) The next thing to do should be to get rid of PyCObject and use a special descendant of type object, instead. Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Sat Mar 25 08:25:03 2006 @@ -18,7 +18,8 @@ class LowLevelDatabase(object): - def __init__(self, translator=None, standalone=False, gcpolicy=None, thread_enabled=False): + def __init__(self, translator=None, standalone=False, gcpolicy=None, thread_enabled=False, + instantiators={}): self.translator = translator self.standalone = standalone self.structdefnodes = {} @@ -34,7 +35,7 @@ self.infs = [] self.namespace = CNameManager() if not standalone: - self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator) + self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator, instantiators) if gcpolicy is None: from pypy.translator.c import gc gcpolicy = gc.RefcountingGcPolicy Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Sat Mar 25 08:25:03 2006 @@ -33,10 +33,11 @@ self.libraries = libraries self.exports = {} - def build_database(self, exports=[]): + def build_database(self, exports=[], instantiators={}): translator = self.translator db = LowLevelDatabase(translator, standalone=self.standalone, - gcpolicy=self.gcpolicy, thread_enabled=self.thread_enabled) + gcpolicy=self.gcpolicy, thread_enabled=self.thread_enabled, + instantiators=instantiators) if self.stackless: from pypy.translator.c.stackless import StacklessData @@ -50,8 +51,7 @@ # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) - # XXX the following has the side effect to generate - # some needed things. Find out why. + # build entrypoint and eventually other things to expose pf = self.getentrypointptr() pfname = db.get(pf) self.exports[self.entrypoint.func_name] = pf Modified: pypy/dist/pypy/translator/c/pyobj.py ============================================================================== --- pypy/dist/pypy/translator/c/pyobj.py (original) +++ pypy/dist/pypy/translator/c/pyobj.py Sat Mar 25 08:25:03 2006 @@ -5,9 +5,10 @@ from pypy.objspace.flow.model import Variable, Constant from pypy.translator.gensupp import builtin_base from pypy.translator.c.support import log +from pypy.translator.c.wrapper import gen_wrapper from pypy.rpython.rarithmetic import r_int, r_uint -from pypy.rpython.lltypesystem.lltype import pyobjectptr, LowLevelType +from pypy.rpython.lltypesystem.lltype import pyobjectptr # XXX maybe this can be done more elegantly: # needed to convince should_translate_attr @@ -24,7 +25,7 @@ reconstruct them. """ - def __init__(self, namespace, getvalue, translator=None): + def __init__(self, namespace, getvalue, translator=None, instantiators={}): self.namespace = namespace self.getvalue = getvalue self.translator = translator @@ -38,6 +39,7 @@ self.debugstack = () # linked list of nested nameof() self.wrappers = {} # {'pycfunctionvariable': ('name', 'wrapperfn')} self.import_hints = IMPORT_HINTS + self.instantiators = instantiators def nameof(self, obj, debug=None): if debug: @@ -167,6 +169,9 @@ def skipped_function(self, func): # debugging only! Generates a placeholder for missing functions # that raises an exception when called. + + # XXX this is broken after the translationcontext change! + # the frozen attribute is gone. What to do? if self.translator.frozen: warning = 'NOT GENERATING' else: @@ -208,7 +213,6 @@ if self.shouldskipfunc(func): return self.skipped_function(func) - from pypy.translator.c.wrapper import gen_wrapper fwrapper = gen_wrapper(func, self.translator) pycfunctionobj = self.uniquename('gfunc_' + func.__name__) self.wrappers[pycfunctionobj] = func.__name__, self.getvalue(fwrapper) @@ -336,6 +340,9 @@ return name def nameof_classobj(self, cls): + if cls in self.instantiators: + return self.wrap_exported_class(cls) + if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): raise Exception, "%r should never be reached" % (cls,) @@ -345,7 +352,7 @@ if issubclass(cls, Exception): # if cls.__module__ == 'exceptions': # don't rely on this, py.magic redefines AssertionError - if getattr(__builtin__,cls.__name__,None) is cls: + if getattr(__builtin__, cls.__name__, None) is cls: name = self.uniquename('gexc_' + cls.__name__) self.initcode_python(name, cls.__name__) return name @@ -521,3 +528,41 @@ co = compile(source, '', 'exec') del source return marshal.dumps(co), originalsource + + # ____________________________________________________________- + # addition for true extension module building + + def wrap_exported_class(self, cls): + metaclass = "type" + name = self.uniquename('gwcls_' + cls.__name__) + basenames = [self.nameof(base) for base in cls.__bases__] + def initclassobj(): + content = cls.__dict__.items() + content.sort() + for key, value in content: + if key.startswith('__'): + if key in ['__module__', '__doc__', '__dict__', + '__weakref__', '__repr__', '__metaclass__']: + continue + if self.shouldskipfunc(value): + log.WARNING("skipped class function: %r" % value) + continue + yield '%s.%s = property(lambda self:%s.__get__(self.__self__))' % ( + name, key, self.nameof(value)) + + baseargs = ", ".join(basenames) + if baseargs: + baseargs = '(%s)' % baseargs + + # fishing for the instantiator + instantiator = self.nameof(self.instantiators[cls]) + a = self.initcode.append + a('class %s%s:' % (name, baseargs) ) + a(' __metaclass__ = type') + a(' __slots__ = ["__self__"] # for PyCObject') + a(' def __new__(cls, *args, **kwds):') + a(' inst = object.__new__(cls)') + a(' inst.__self__ = %s()' % instantiator) + a(' return inst') + self.later(initclassobj()) + return name Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Sat Mar 25 08:25:03 2006 @@ -4,6 +4,7 @@ from pypy.rpython import extregistry from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype +from pypy.rpython.objectmodel import instantiate P = False # debug printing @@ -18,7 +19,7 @@ missing = [object] * (func.func_code.co_argcount - len(argstypelist)) return missing + argstypelist -def getcompiled(func, view=conftest.option.view, inline_threshold=1, +def get_compiled_module(func, view=conftest.option.view, inline_threshold=1, use_boehm=False, exports=[]): from pypy.translator.translator import TranslationContext from pypy.translator.backendopt.all import backend_optimizations @@ -34,10 +35,15 @@ t.viewcg() rtyper = t.buildrtyper() bk = rtyper.annotator.bookkeeper + instantiators = {} for obj in exports: if isinstance(obj, type): - cdef = bk.getuniqueclassdef(obj) - bk.needs_generic_instantiate[cdef] = True + cls = obj + def make(): + return instantiate(cls) + make.__name__ = cls.__name__ + '__new__' + t.annotator.build_types(make, []) + instantiators[cls] = make rtyper.specialize() if view: t.viewcg() @@ -53,13 +59,17 @@ cbuilder = CExtModuleBuilder(t, func, gcpolicy=gcpolicy) # explicit build of database - db = cbuilder.build_database(exports=exports) + db = cbuilder.build_database(exports=exports, instantiators=instantiators) cbuilder.generate_source(db) cbuilder.compile() if view: t.viewcg() - return getattr(cbuilder.import_module(), func.__name__) + return cbuilder.import_module() + +def getcompiled(func, *args, **kwds): + module = get_compiled_module(func, *args, **kwds) + return getattr(module, func.__name__) # _______________________________________________- # stubs for special annotation/rtyping @@ -230,9 +240,10 @@ if P: print ret assert ret[0] == 1 -# exposing and using classes. almost ready, missing spots in the python delegation +# exposing and using classes from a generasted extension module def test_expose_classes(): - f = getcompiled(democlass_helper2, use_boehm=not True, exports=[ + m = get_compiled_module(democlass_helper2, use_boehm=not True, exports=[ DemoClass, DemoSubclass, DemoNotAnnotated]) - res = f(2, 3) - if P: print 55*'-', res + obj = m.DemoClass(2, 3) + res = obj.demo() + assert res == DemoClass(2, 3).demo() From antocuni at codespeak.net Sat Mar 25 12:07:23 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 25 Mar 2006 12:07:23 +0100 (CET) Subject: [pypy-svn] r24991 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060325110723.E047A10124@code0.codespeak.net> Author: antocuni Date: Sat Mar 25 12:07:11 2006 New Revision: 24991 Added: pypy/dist/pypy/translator/cli/test/test_cast.py (contents, props changed) Modified: pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/runtest.py pypy/dist/pypy/translator/cli/test/test_op.py Log: Add support for casts Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Sat Mar 25 12:07:11 2006 @@ -155,18 +155,22 @@ 'ullong_gt': 'cgt.un', 'ullong_ge': _not('clt.un'), - 'cast_bool_to_int': None, - 'cast_bool_to_uint': None, - 'cast_bool_to_float': None, + # when casting from bool we want that every truth value is casted + # to 1: we can't simply DoNothing, because the CLI stack could + # contains a truth value not equal to 1, so we should use the !=0 + # trick. + 'cast_bool_to_int': [PushArgs, 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_uint': [PushArgs, 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_float': [PushArgs, 'ldc.i4 0', 'ceq']+Not+['conv.r8'], 'cast_char_to_int': None, 'cast_unichar_to_int': None, 'cast_int_to_char': None, 'cast_int_to_unichar': None, - 'cast_int_to_uint': None, - 'cast_int_to_float': None, - 'cast_int_to_longlong': None, - 'cast_uint_to_int': None, - 'cast_float_to_int': None, - 'cast_float_to_uint': None, - 'truncate_longlong_to_int': None + 'cast_int_to_uint': DoNothing, + 'cast_int_to_float': 'conv.r8', + 'cast_int_to_longlong': 'conv.i8', + 'cast_uint_to_int': DoNothing, + 'cast_float_to_int': 'conv.i4', + 'cast_float_to_uint': 'conv.i4', + 'truncate_longlong_to_int': 'conv.i4', } Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Sat Mar 25 12:07:11 2006 @@ -61,7 +61,7 @@ 'unsigned int32': 'ToUInt32', 'int64': 'ToInt64', 'unsigned int64': 'ToUInt64', - 'bool': 'ToBool', + 'bool': 'ToBoolean', 'float64': 'ToDouble' } Added: pypy/dist/pypy/translator/cli/test/test_cast.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/test/test_cast.py Sat Mar 25 12:07:11 2006 @@ -0,0 +1,46 @@ +import sys + +from pypy.translator.cli.test.runtest import check +from pypy.rpython.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask + +def to_int(x): + return int(x) + +def to_uint(x): + return r_uint(x) + +def to_float(x): + return float(x) + +def to_longlong(x): + return r_longlong(x) + + +def test_bool_to_int(): + check(to_int, [bool], (True,)) + check(to_int, [bool], (False,)) + +def test_bool_to_uint(): + check(to_uint, [bool], (True,)) + check(to_uint, [bool], (False,)) + +def test_bool_to_float(): + check(to_float, [bool], (True,)) + check(to_float, [bool], (False,)) + +def test_int_to_uint(): + check(to_uint, [int], (42,)) + +def test_int_to_float(): + check(to_float, [int], (42,)) + +def test_int_to_longlong(): + check(to_longlong, [int], (42,)) + +def test_uint_to_int(): + def uint_to_int(x): + return intmask(x) + check(uint_to_int, [r_uint], (sys.maxint+1,)) + +def test_float_to_int(): + check(to_int, [float], (42.5,)) Modified: pypy/dist/pypy/translator/cli/test/test_op.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_op.py (original) +++ pypy/dist/pypy/translator/cli/test/test_op.py Sat Mar 25 12:07:11 2006 @@ -50,4 +50,3 @@ def op_any_operations(x, y): return (x*y) + (x-y) + (x/y) -print op_int_uint_bitwise(r_uint(42), r_uint(13)) From nik at codespeak.net Sat Mar 25 13:05:27 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Sat, 25 Mar 2006 13:05:27 +0100 (CET) Subject: [pypy-svn] r24993 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20060325120527.119941010F@code0.codespeak.net> Author: nik Date: Sat Mar 25 13:05:26 2006 New Revision: 24993 Modified: pypy/dist/pypy/rpython/lltypesystem/rtuple.py pypy/dist/pypy/rpython/ootypesystem/rtuple.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: support tuple iterators for ootype. in theory, ootypesystem now has full support for tuples. Modified: pypy/dist/pypy/rpython/lltypesystem/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rtuple.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rtuple.py Sat Mar 25 13:05:26 2006 @@ -1,16 +1,9 @@ -import operator from pypy.annotation.pairtype import pairtype -from pypy.annotation import model as annmodel -from pypy.objspace.flow.model import Constant -from pypy.rpython.error import TyperError -from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst -from pypy.rpython.rmodel import IteratorRepr -from pypy.rpython.rmodel import externalvsinternal +from pypy.rpython.rmodel import inputconst from pypy.rpython.robject import PyObjRepr, pyobj_repr -from pypy.rpython.rtuple import AbstractTupleRepr +from pypy.rpython.rtuple import AbstractTupleRepr, AbstractTupleIteratorRepr from pypy.rpython.lltypesystem.lltype import \ Ptr, GcStruct, Void, Signed, malloc, typeOf, nullptr -from pypy.rpython.rarithmetic import intmask # ____________________________________________________________ # @@ -63,11 +56,6 @@ hop.gendirectcall(rlist.ll_setitem_nonneg, v_func, vlist, cindex, vitem) return vlist - def make_iterator_repr(self): - if len(self.items_r) == 1: - return Length1TupleIteratorRepr(self) - raise TyperError("can only iterate over tuples of length 1 for now") - def getitem(self, llops, v_tuple, index): # ! returns internal repr lowleveltype name = self.fieldnames[index] llresult = self.lltypes[index] @@ -113,24 +101,16 @@ # # Iteration. -class Length1TupleIteratorRepr(IteratorRepr): +class Length1TupleIteratorRepr(AbstractTupleIteratorRepr): def __init__(self, r_tuple): self.r_tuple = r_tuple self.lowleveltype = Ptr(GcStruct('tuple1iter', ('tuple', r_tuple.lowleveltype))) + self.ll_tupleiter = ll_tupleiter + self.ll_tuplenext = ll_tuplenext - def newiter(self, hop): - v_tuple, = hop.inputargs(self.r_tuple) - citerptr = hop.inputconst(Void, self.lowleveltype) - return hop.gendirectcall(ll_tupleiter, citerptr, v_tuple) - - def rtype_next(self, hop): - v_iter, = hop.inputargs(self) - hop.has_implicit_exception(StopIteration) # record that we know about it - hop.exception_is_here() - v = hop.gendirectcall(ll_tuplenext, v_iter) - return hop.llops.convertvar(v, self.r_tuple.items_r[0], self.r_tuple.external_items_r[0]) +TupleRepr.IteratorRepr = Length1TupleIteratorRepr def ll_tupleiter(ITERPTR, tuple): iter = malloc(ITERPTR.TO) Modified: pypy/dist/pypy/rpython/ootypesystem/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rtuple.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rtuple.py Sat Mar 25 13:05:26 2006 @@ -1,9 +1,5 @@ -from pypy.annotation.pairtype import pairtype -from pypy.objspace.flow.model import Constant -from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst -from pypy.rpython.rmodel import externalvsinternal -from pypy.rpython.error import TyperError -from pypy.rpython.rtuple import AbstractTupleRepr +from pypy.rpython.rmodel import inputconst +from pypy.rpython.rtuple import AbstractTupleRepr, AbstractTupleIteratorRepr from pypy.rpython.ootypesystem import ootype @@ -55,3 +51,43 @@ def rtype_newtuple(hop): return TupleRepr._rtype_newtuple(hop) +# ____________________________________________________________ +# +# Iteration. + +_tuple_iter_types = {} + +def tuple_iter_type(r_tuple): + key = r_tuple.lowleveltype + if _tuple_iter_types.has_key(key): + return _tuple_iter_types[key] + else: + INST = ootype.Instance("TupleIter", ootype.ROOT, + {"tuple": r_tuple.lowleveltype}) + _tuple_iter_types[key] = INST + return INST + +class Length1TupleIteratorRepr(AbstractTupleIteratorRepr): + + def __init__(self, r_tuple): + self.r_tuple = r_tuple + self.lowleveltype = tuple_iter_type(r_tuple) + self.ll_tupleiter = ll_tupleiter + self.ll_tuplenext = ll_tuplenext + +TupleRepr.IteratorRepr = Length1TupleIteratorRepr + +def ll_tupleiter(ITERINST, tuple): + iter = ootype.new(ITERINST) + iter.tuple = tuple + return iter + +def ll_tuplenext(iter): + # for iterating over length 1 tuples only! + t = iter.tuple + if t: + iter.tuple = ootype.null(ootype.typeOf(t)) + return t.item0 + else: + raise StopIteration + Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Sat Mar 25 13:05:26 2006 @@ -6,9 +6,7 @@ from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst from pypy.rpython.rmodel import IteratorRepr from pypy.rpython.rmodel import externalvsinternal -from pypy.rpython.robject import PyObjRepr, pyobj_repr -from pypy.rpython.lltypesystem.lltype import \ - Ptr, GcStruct, Void, Signed, malloc, typeOf, nullptr +from pypy.rpython.lltypesystem.lltype import Void, Signed from pypy.rpython.rarithmetic import intmask class __extend__(annmodel.SomeTuple): @@ -128,6 +126,12 @@ def get_ll_hash_function(self): return gen_hash_function(self.items_r) + def make_iterator_repr(self): + if len(self.items_r) == 1: + # subclasses are supposed to set the IteratorRepr attribute + return self.IteratorRepr(self) + raise TyperError("can only iterate over tuples of length 1 for now") + class __extend__(pairtype(AbstractTupleRepr, IntegerRepr)): @@ -187,3 +191,18 @@ return r_from.newtuple(llops, r_to, items_v) return NotImplemented + +class AbstractTupleIteratorRepr(IteratorRepr): + + def newiter(self, hop): + v_tuple, = hop.inputargs(self.r_tuple) + citerptr = hop.inputconst(Void, self.lowleveltype) + return hop.gendirectcall(self.ll_tupleiter, citerptr, v_tuple) + + def rtype_next(self, hop): + v_iter, = hop.inputargs(self) + hop.has_implicit_exception(StopIteration) # record that we know about it + hop.exception_is_here() + v = hop.gendirectcall(self.ll_tuplenext, v_iter) + return hop.llops.convertvar(v, self.r_tuple.items_r[0], self.r_tuple.external_items_r[0]) + Modified: pypy/dist/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rtuple.py (original) +++ pypy/dist/pypy/rpython/test/test_rtuple.py Sat Mar 25 13:05:26 2006 @@ -196,34 +196,33 @@ res = self.interpret(f, [2, 3]) assert res._obj.items == [2, 3] + def test_tuple_iterator_length1(self): + def f(i): + total = 0 + for x in (i,): + total += x + return total + res = self.interpret(f, [93813]) + assert res == 93813 + + def test_inst_tuple_iter(self): + class A: + pass + class B(A): + pass + + def f(i): + if i: + x = (A(),) + else: + x = (B(),) + l = None + for y in x: + l = y + return l -def test_tuple_iterator_length1(): - def f(i): - total = 0 - for x in (i,): - total += x - return total - res = interpret(f, [93813]) - assert res == 93813 - -def test_inst_tuple_iter(): - class A: - pass - class B(A): - pass - - def f(i): - if i: - x = (A(),) - else: - x = (B(),) - l = [] - for y in x: - l.append(y) - return l[0] - - res = interpret(f, [0]) - assert ''.join(res.super.typeptr.name) == "B\00" + res = self.interpret(f, [0]) + assert self.class_name(res) == "B" class TestLLTuple(AbstractTestRTuple): From nik at codespeak.net Sat Mar 25 13:48:57 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Sat, 25 Mar 2006 13:48:57 +0100 (CET) Subject: [pypy-svn] r24994 - pypy/dist/pypy/translator/squeak/test Message-ID: <20060325124857.7A65F10127@code0.codespeak.net> Author: nik Date: Sat Mar 25 13:48:56 2006 New Revision: 24994 Added: pypy/dist/pypy/translator/squeak/test/test_datastructure.py Log: add some tuple tests to gensqueak. tuple iteration doesn't really work right now, because handling of loops is generally very primitive in gensqueak. Added: pypy/dist/pypy/translator/squeak/test/test_datastructure.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/squeak/test/test_datastructure.py Sat Mar 25 13:48:56 2006 @@ -0,0 +1,32 @@ +from pypy.translator.squeak.test.runtest import compile_function + +class TestTuple: + + def test_twotuple(self): + def f(i): + # Use two different two-tuples to make sure gensqueak can cope + # with the two different classes. + b = (True, i) + if b[0]: + i = b[1] + 1 + if i > 0: + return (i, 1) + else: + return (i, -1) + def g(i): + return f(i)[1] + fn = compile_function(g, [int]) + res = fn(2) + assert res == "1" + res = fn(-2) + assert res == "-1" + + def DONT_test_tupleiter(self): + def f(i): + t = (i,) + for x in t: + i += x + return t + fn = compile_function(f, [int]) + res = fn(2) + assert res == "4" From arigo at codespeak.net Sat Mar 25 14:27:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Mar 2006 14:27:56 +0100 (CET) Subject: [pypy-svn] r24996 - in pypy/dist/pypy/jit: . test Message-ID: <20060325132756.2319C10135@code0.codespeak.net> Author: arigo Date: Sat Mar 25 14:27:55 2006 New Revision: 24996 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: (arigo, pedronis yesterday evening) Intermediate check-in: VirtualRedBox. Started to move some rtimeshift functions to be methods of the RedBox subclasses. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Sat Mar 25 14:27:55 2006 @@ -55,7 +55,11 @@ try: return self.red_reprs[lowleveltype] except KeyError: - r = RedRepr(lowleveltype, self.timeshifter) + redreprcls = RedRepr + if isinstance(lowleveltype, lltype.Ptr): + if isinstance(lowleveltype.TO, lltype.Struct): + redreprcls = RedStructRepr + r = redreprcls(lowleveltype, self.timeshifter) self.red_reprs[lowleveltype] = r return r @@ -323,20 +327,17 @@ def residual_values(self, ll_value): return [ll_value] + +class RedStructRepr(RedRepr): + ll_factory = None + def create(self, hop): + if self.ll_factory is None: + T = self.original_concretetype.TO + self.ll_factory = rtimeshift.make_virtualredbox_factory_for_struct(T) ts = self.timeshifter - s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) - RESTYPE = self.original_concretetype - gv_type = rgenop.constTYPE(RESTYPE.TO) - c_type = hop.inputconst(rgenop.CONSTORVAR, gv_type) - gv_resulttype = rgenop.constTYPE(RESTYPE) - c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) - v_jitstate = hop.llops.getjitstate() - - return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_malloc, - [ts.s_JITState, s_CONSTORVAR, s_CONSTORVAR], - [v_jitstate, c_type, c_resulttype], - ts.s_RedBox) + return hop.llops.genmixlevelhelpercall(self.ll_factory, + [], [], ts.s_RedBox) class BlueRepr(Repr): Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Sat Mar 25 14:27:55 2006 @@ -1,3 +1,4 @@ +import operator from pypy.rpython.lltypesystem import lltype, lloperation, llmemory from pypy.rpython import rgenop @@ -31,6 +32,23 @@ def same_constant(self, other): return False + # generic implementation of some operations + def op_getfield(self, jitstate, fielddesc, gv_fieldname, gv_resulttype): + op_args = lltype.malloc(VARLIST.TO, 2) + op_args[0] = self.getgenvar() + op_args[1] = gv_fieldname + genvar = rgenop.genop(jitstate.curblock, 'getfield', op_args, + gv_resulttype) + return VarRedBox(genvar) + + def op_setfield(self, jitstate, fielddesc, gv_fieldname, valuebox): + op_args = lltype.malloc(VARLIST.TO, 3) + op_args[0] = self.getgenvar() + op_args[1] = gv_fieldname + op_args[2] = valuebox.getgenvar() + rgenop.genop(jitstate.curblock, 'setfield', op_args, + gv_Void) + class VarRedBox(RedBox): "A red box that contains a run-time variable." @@ -68,6 +86,33 @@ assert isinstance(box, ContainerRedBox) return box.content_addr + +class VirtualRedBox(RedBox): + "A red box that contains (for now) a virtual Struct." + + def __init__(self, content_boxes): + self.content_boxes = content_boxes[:] + + def getgenvar(self): # no support at the moment + raise RuntimeError("cannot force virtual containers") + + def op_getfield(self, jitstate, fielddesc, gv_fieldname, gv_returntype): + return self.content_boxes[fielddesc.fieldindex] + + def op_setfield(self, jitstate, fielddesc, gv_fieldname, valuebox): + self.content_boxes[fielddesc.fieldindex] = valuebox + +def make_virtualredbox_factory_for_struct(T): + defls = [] + for name in T._names: + FIELDTYPE = T._flds[name] + defaultvalue = FIELDTYPE._defl() + defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) + defls.append(defaultbox) + def ll_factory(): + return VirtualRedBox(defls) + return ll_factory + class ConstRedBox(RedBox): "A red box that contains a run-time constant." @@ -206,6 +251,12 @@ self.PTRTYPE = PTRTYPE self.immutable = PTRTYPE.TO._hints.get('immutable', False) self.fieldname = fieldname + if isinstance(PTRTYPE.TO, lltype.Struct): + try: + self.fieldindex = operator.indexOf(PTRTYPE.TO._names, fieldname) + except ValueError: + raise ValueError("field not found: %r in %r" % (fieldname, + PTRTYPE.TO)) def _freeze_(self): return True @@ -227,24 +278,13 @@ if fielddesc.immutable and isinstance(argbox, ConstRedBox): res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) return ConstRedBox.ll_fromvalue(res) - op_args = lltype.malloc(VARLIST.TO, 2) - op_args[0] = argbox.getgenvar() - op_args[1] = gv_fieldname - genvar = rgenop.genop(jitstate.curblock, 'getfield', op_args, - gv_resulttype) - return VarRedBox(genvar) + return argbox.op_getfield(jitstate, fielddesc, gv_fieldname, gv_resulttype) gv_Void = rgenop.constTYPE(lltype.Void) def ll_generate_setfield(jitstate, fielddesc, destbox, gv_fieldname, valuebox): - op_args = lltype.malloc(VARLIST.TO, 3) - op_args[0] = destbox.getgenvar() - op_args[1] = gv_fieldname - op_args[2] = valuebox.getgenvar() - rgenop.genop(jitstate.curblock, 'setfield', op_args, - gv_Void) - + destbox.op_setfield(jitstate, fielddesc, gv_fieldname, valuebox) def ll_generate_getsubstruct(jitstate, fielddesc, argbox, @@ -273,12 +313,12 @@ gv_resulttype) return VarRedBox(genvar) -def ll_generate_malloc(jitstate, gv_type, gv_resulttype): - op_args = lltype.malloc(VARLIST.TO, 1) - op_args[0] = gv_type - genvar = rgenop.genop(jitstate.curblock, 'malloc', op_args, - gv_resulttype) - return VarRedBox(genvar) +##def ll_generate_malloc(jitstate, gv_type, gv_resulttype): +## op_args = lltype.malloc(VARLIST.TO, 1) +## op_args[0] = gv_type +## genvar = rgenop.genop(jitstate.curblock, 'malloc', op_args, +## gv_resulttype) +## return VarRedBox(genvar) # ____________________________________________________________ # other jitstate/graph level operations Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Sat Mar 25 14:27:55 2006 @@ -260,6 +260,7 @@ 'int_sub': 1} def test_simple_struct(): + py.test.skip("pending rpython.test_rpbc.test_disjoint_pbcs") S = lltype.GcStruct('helloworld', ('hello', lltype.Signed), ('world', lltype.Signed), hints={'immutable': True}) @@ -325,6 +326,7 @@ assert insns == {} def test_degenerated_merge_substructure(): + py.test.skip("re in-progress") S = lltype.GcStruct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) @@ -363,7 +365,6 @@ # this checks that red boxes are able to be virtualized dynamically by # the compiler (the P_NOVIRTUAL policy prevents the hint-annotator from # marking variables in blue) - py.test.skip("in-progress") S = lltype.GcStruct('S', ('n', lltype.Signed)) def ll_function(n): s = lltype.malloc(S) From arigo at codespeak.net Sat Mar 25 18:54:32 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Mar 2006 18:54:32 +0100 (CET) Subject: [pypy-svn] r24999 - pypy/dist/pypy/translator/c Message-ID: <20060325175432.9E171100C3@code0.codespeak.net> Author: arigo Date: Sat Mar 25 18:54:31 2006 New Revision: 24999 Modified: pypy/dist/pypy/translator/c/pyobj.py Log: Missing import. Modified: pypy/dist/pypy/translator/c/pyobj.py ============================================================================== --- pypy/dist/pypy/translator/c/pyobj.py (original) +++ pypy/dist/pypy/translator/c/pyobj.py Sat Mar 25 18:54:31 2006 @@ -8,7 +8,7 @@ from pypy.translator.c.wrapper import gen_wrapper from pypy.rpython.rarithmetic import r_int, r_uint -from pypy.rpython.lltypesystem.lltype import pyobjectptr +from pypy.rpython.lltypesystem.lltype import pyobjectptr, LowLevelType # XXX maybe this can be done more elegantly: # needed to convince should_translate_attr From arigo at codespeak.net Sat Mar 25 19:20:02 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Mar 2006 19:20:02 +0100 (CET) Subject: [pypy-svn] r25000 - in pypy/dist/pypy: rpython rpython/l3interp rpython/lltypesystem rpython/test translator/c/src translator/c/test Message-ID: <20060325182002.EB9CA100C3@code0.codespeak.net> Author: arigo Date: Sat Mar 25 19:19:57 2006 New Revision: 25000 Modified: pypy/dist/pypy/rpython/l3interp/model.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/rpython/rfloat.py pypy/dist/pypy/rpython/rint.py pypy/dist/pypy/rpython/test/test_llinterp.py pypy/dist/pypy/rpython/test/test_rint.py pypy/dist/pypy/translator/c/src/float.h pypy/dist/pypy/translator/c/src/int.h pypy/dist/pypy/translator/c/test/test_typed.py Log: Remove some of the division low-level operations. Now we only have xxx_floordiv for integer types, and float_truediv for floats. The high-level operations are mapped to one of these, possibly with conversions (inserted automagically by the rtyper). Modified: pypy/dist/pypy/rpython/l3interp/model.py ============================================================================== --- pypy/dist/pypy/rpython/l3interp/model.py (original) +++ pypy/dist/pypy/rpython/l3interp/model.py Sat Mar 25 19:19:57 2006 @@ -31,10 +31,10 @@ 'flavored_free', 'flavored_malloc', #float operations: - 'float_abs', 'float_add', 'float_div', 'float_eq', 'float_floor', - 'float_floordiv', 'float_fmod', 'float_ge', 'float_gt', 'float_invert', + 'float_abs', 'float_add', 'float_truediv', 'float_eq', 'float_floor', + 'float_fmod', 'float_ge', 'float_gt', 'float_invert', 'float_is_true', 'float_le', 'float_lt', 'float_mod', 'float_mul', - 'float_ne', 'float_neg', 'float_sub', 'float_truediv', + 'float_ne', 'float_neg', 'float_sub', #array operations: 'getarrayitem_int', 'getarrayitem_ptr', @@ -48,15 +48,14 @@ #integer operations: 'int_abs', 'int_abs_ovf', 'int_add', 'int_add_ovf', 'int_and', - 'int_and_ovf', 'int_div', 'int_div_ovf', 'int_eq', 'int_eq_ovf', + 'int_and_ovf', 'int_eq', 'int_eq_ovf', 'int_floordiv', 'int_floordiv_ovf', 'int_floordiv_ovf_zer', 'int_ge', 'int_ge_ovf', 'int_gt', 'int_gt_ovf', 'int_invert', 'int_invert_ovf', 'int_is_true', 'int_is_true_ovf', 'int_le', 'int_le_ovf', 'int_lshift', 'int_lshift_ovf', 'int_lt', 'int_lt_ovf', 'int_mod', 'int_mod_ovf', 'int_mod_ovf_zer', 'int_mul', 'int_mul_ovf', 'int_ne', 'int_ne_ovf', 'int_neg', 'int_neg_ovf', 'int_or', 'int_or_ovf', 'int_rshift', - 'int_rshift_ovf', 'int_sub', 'int_sub_ovf', 'int_truediv', - 'int_truediv_ovf', 'int_xor', 'int_xor_ovf', + 'int_rshift_ovf', 'int_sub', 'int_sub_ovf', 'int_xor', 'int_xor_ovf', #regular object memory operations: 'keepalive', 'malloc', 'malloc_varsize', @@ -71,10 +70,10 @@ 'same_as', #operations with unsigned integers: - 'uint_abs', 'uint_add', 'uint_and', 'uint_div', 'uint_eq', + 'uint_abs', 'uint_add', 'uint_and', 'uint_eq', 'uint_floordiv', 'uint_ge', 'uint_gt', 'uint_invert', 'uint_is_true', 'uint_le', 'uint_lshift', 'uint_lt', 'uint_mod', 'uint_mul', 'uint_ne', - 'uint_neg', 'uint_or', 'uint_rshift', 'uint_sub', 'uint_truediv', + 'uint_neg', 'uint_or', 'uint_rshift', 'uint_sub', 'uint_xor', #operations with unicode characters Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Sat Mar 25 19:19:57 2006 @@ -115,7 +115,6 @@ 'lt': True, 'le': True, 'eq': True, 'ne': True, 'is_true': True} -ops_returning_a_float = {'truediv': True} def checkptr(ptr): return isinstance(lltype.typeOf(ptr), lltype.Ptr) @@ -689,7 +688,7 @@ for typ in (float, int, r_uint, r_longlong, r_ulonglong): typname = typ.__name__ - optup = ('add', 'sub', 'mul', 'div', 'truediv', 'floordiv', + optup = ('add', 'sub', 'mul', 'truediv', 'floordiv', 'mod', 'gt', 'lt', 'ge', 'ne', 'le', 'eq',) if typ is r_uint: opnameprefix = 'uint' @@ -703,8 +702,11 @@ optup += 'and_', 'or_', 'lshift', 'rshift', 'xor' for opname in optup: assert opname in opimpls - if typ is int and opname not in ops_returning_a_bool \ - and opname not in ops_returning_a_float: + if typ is float and opname == 'floordiv': + continue # 'floordiv' is for integer types + if typ is not float and opname == 'truediv': + continue # 'truediv' is for floats only + if typ is int and opname not in ops_returning_a_bool: adjust_result = 'intmask' else: adjust_result = '' Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Sat Mar 25 19:19:57 2006 @@ -63,7 +63,6 @@ # XXX Some clean-ups are needed: # * many exception-raising operations are being replaced by calls to helpers # * there are still many _ovf operations that cannot really raise OverflowError -# * the div/truediv/floordiv mess needs to be sorted out and reduced # * float_mod vs float_fmod ? # Run test_lloperation after changes. Feel free to clean up LLInterpreter too :-) @@ -96,8 +95,6 @@ 'int_add': LLOp(canfold=True), 'int_sub': LLOp(canfold=True), 'int_mul': LLOp(canfold=True), - 'int_div': LLOp(canfold=True), - 'int_truediv': LLOp(canfold=True), 'int_floordiv': LLOp(canfold=True), 'int_mod': LLOp(canfold=True), 'int_lt': LLOp(canfold=True), @@ -114,8 +111,6 @@ 'int_add_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_sub_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_mul_ovf': LLOp(canfold=True, canraise=(OverflowError,)), - 'int_div_ovf': LLOp(canfold=True, canraise=(OverflowError,)), - 'int_truediv_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_floordiv_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_mod_ovf': LLOp(canfold=True, canraise=(OverflowError,)), 'int_lt_ovf': LLOp(canfold=True, canraise=(OverflowError,)), @@ -140,8 +135,6 @@ 'uint_add': LLOp(canfold=True), 'uint_sub': LLOp(canfold=True), 'uint_mul': LLOp(canfold=True), - 'uint_div': LLOp(canfold=True), - 'uint_truediv': LLOp(canfold=True), 'uint_floordiv': LLOp(canfold=True), 'uint_mod': LLOp(canfold=True), 'uint_lt': LLOp(canfold=True), @@ -163,9 +156,7 @@ 'float_add': LLOp(canfold=True), 'float_sub': LLOp(canfold=True), 'float_mul': LLOp(canfold=True), - 'float_div': LLOp(canfold=True), 'float_truediv': LLOp(canfold=True), - 'float_floordiv': LLOp(canfold=True), 'float_mod': LLOp(canfold=True), 'float_lt': LLOp(canfold=True), 'float_le': LLOp(canfold=True), @@ -184,8 +175,6 @@ 'llong_add': LLOp(canfold=True), 'llong_sub': LLOp(canfold=True), 'llong_mul': LLOp(canfold=True), - 'llong_div': LLOp(canfold=True), - 'llong_truediv': LLOp(canfold=True), 'llong_floordiv': LLOp(canfold=True), 'llong_mod': LLOp(canfold=True), 'llong_lt': LLOp(canfold=True), @@ -203,8 +192,6 @@ 'ullong_add': LLOp(canfold=True), 'ullong_sub': LLOp(canfold=True), 'ullong_mul': LLOp(canfold=True), - 'ullong_div': LLOp(canfold=True), - 'ullong_truediv': LLOp(canfold=True), 'ullong_floordiv': LLOp(canfold=True), 'ullong_mod': LLOp(canfold=True), 'ullong_lt': LLOp(canfold=True), Modified: pypy/dist/pypy/rpython/rfloat.py ============================================================================== --- pypy/dist/pypy/rpython/rfloat.py (original) +++ pypy/dist/pypy/rpython/rfloat.py Sat Mar 25 19:19:57 2006 @@ -41,13 +41,16 @@ rtype_inplace_mul = rtype_mul - def rtype_div(_, hop): - # turn 'div' on floats into 'truediv' + def rtype_truediv(_, hop): return _rtype_template(hop, 'truediv') - rtype_inplace_div = rtype_div - rtype_truediv = rtype_div - rtype_inplace_truediv = rtype_div + rtype_inplace_truediv = rtype_truediv + + # turn 'div' on floats into 'truediv' + rtype_div = rtype_truediv + rtype_inplace_div = rtype_inplace_truediv + + # 'floordiv' on floats not supported in RPython def rtype_pow(_, hop): s_float3 = hop.args_s[2] Modified: pypy/dist/pypy/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/dist/pypy/rpython/rint.py Sat Mar 25 19:19:57 2006 @@ -74,14 +74,6 @@ def rtype_mul_ovf(_, hop): return _rtype_template(hop, 'mul_ovf') - def rtype_div(_, hop): - # turn 'div' on integers into 'floordiv' - return _rtype_template(hop, 'floordiv', [ZeroDivisionError]) - rtype_inplace_div = rtype_div - - def rtype_div_ovf(_, hop): - return _rtype_template(hop, 'div_ovf', [ZeroDivisionError]) - def rtype_floordiv(_, hop): return _rtype_template(hop, 'floordiv', [ZeroDivisionError]) rtype_inplace_floordiv = rtype_floordiv @@ -89,9 +81,12 @@ def rtype_floordiv_ovf(_, hop): return _rtype_template(hop, 'floordiv_ovf', [ZeroDivisionError]) - def rtype_truediv(_, hop): - return _rtype_template(hop, 'truediv', [ZeroDivisionError]) - rtype_inplace_truediv = rtype_truediv + # turn 'div' on integers into 'floordiv' + rtype_div = rtype_floordiv + rtype_inplace_div = rtype_inplace_floordiv + rtype_div_ovf = rtype_floordiv_ovf + + # 'def rtype_truediv' is delegated to the superclass FloatRepr def rtype_mod(_, hop): return _rtype_template(hop, 'mod', [ZeroDivisionError]) Modified: pypy/dist/pypy/rpython/test/test_llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_llinterp.py (original) +++ pypy/dist/pypy/rpython/test/test_llinterp.py Sat Mar 25 19:19:57 2006 @@ -290,7 +290,7 @@ res = interpret(g, [-15]) assert res == 15 -def test_div_ovf_zer(): +def test_floordiv_ovf_zer(): import sys def f(x): try: @@ -356,15 +356,6 @@ assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 0 -def test_int_truediv(): - from pypy.rpython.lltypesystem.lltype import Float - def f(i, j): - return llop.int_truediv(Float, i, j) - for args in (4, 2), (3, 4): - res = interpret(f, list(args)) - assert isinstance(res, float) - assert res == float(args[0]) / args[1] - #__________________________________________________________________ # # Test objects and instances Modified: pypy/dist/pypy/rpython/test/test_rint.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rint.py (original) +++ pypy/dist/pypy/rpython/test/test_rint.py Sat Mar 25 19:19:57 2006 @@ -139,3 +139,11 @@ return space.wrap(x) res = interpret(wrap, [r_longlong(0)]) assert res == 0 + +def test_truediv(): + import operator + def f(n, m): + return operator.truediv(n, m) + res = interpret(f, [20, 4]) + assert type(res) is float + assert res == 5.0 Modified: pypy/dist/pypy/translator/c/src/float.h ============================================================================== --- pypy/dist/pypy/translator/c/src/float.h (original) +++ pypy/dist/pypy/translator/c/src/float.h Sat Mar 25 19:19:57 2006 @@ -26,8 +26,7 @@ #define OP_FLOAT_ADD(x,y,r,err) r = x + y #define OP_FLOAT_SUB(x,y,r,err) r = x - y #define OP_FLOAT_MUL(x,y,r,err) r = x * y -#define OP_FLOAT_DIV(x,y,r,err) r = x / y -#define OP_FLOAT_TRUEDIV(x,y,r,err) OP_FLOAT_DIV(x,y,r,err) +#define OP_FLOAT_TRUEDIV(x,y,r,err) r = x / y #define OP_FLOAT_POW(x,y,r,err) r = pow(x, y) /*** conversions ***/ Modified: pypy/dist/pypy/translator/c/src/int.h ============================================================================== --- pypy/dist/pypy/translator/c/src/int.h (original) +++ pypy/dist/pypy/translator/c/src/int.h Sat Mar 25 19:19:57 2006 @@ -290,7 +290,7 @@ #define OP_LLONG_ADD OP_INT_ADD #define OP_LLONG_SUB OP_INT_SUB #define OP_LLONG_MUL OP_INT_MUL -#define OP_LLONG_DIV OP_INT_DIV +#define OP_LLONG_FLOORDIV OP_INT_FLOORDIV #define OP_LLONG_EQ OP_INT_EQ #define OP_LLONG_NE OP_INT_NE Modified: pypy/dist/pypy/translator/c/test/test_typed.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_typed.py (original) +++ pypy/dist/pypy/translator/c/test/test_typed.py Sat Mar 25 19:19:57 2006 @@ -205,7 +205,7 @@ fn = self.getcompiled(snippet.add_func) raises(OverflowError, fn, sys.maxint) - def test_int_div_ovf_zer(self): + def test_int_floordiv_ovf_zer(self): fn = self.getcompiled(snippet.div_func) raises(OverflowError, fn, -1) raises(ZeroDivisionError, fn, 0) From antocuni at codespeak.net Sat Mar 25 20:16:23 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 25 Mar 2006 20:16:23 +0100 (CET) Subject: [pypy-svn] r25002 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060325191623.06239100CA@code0.codespeak.net> Author: antocuni Date: Sat Mar 25 20:16:12 2006 New Revision: 25002 Modified: pypy/dist/pypy/translator/cli/conftest.py pypy/dist/pypy/translator/cli/test/runtest.py Log: Fixed conftest-related bug Modified: pypy/dist/pypy/translator/cli/conftest.py ============================================================================== --- pypy/dist/pypy/translator/cli/conftest.py (original) +++ pypy/dist/pypy/translator/cli/conftest.py Sat Mar 25 20:16:12 2006 @@ -1,5 +1,4 @@ import py -from pypy import conftest Option = py.test.Config.Option Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Sat Mar 25 20:16:12 2006 @@ -6,6 +6,7 @@ from pypy.tool.udir import udir from pypy.translator.translator import TranslationContext from pypy.translator.cli import conftest +from pypy.conftest import option from pypy.translator.cli.gencli import GenCli from pypy.translator.cli.function import Node from pypy.translator.cli.cts import graph_to_signature @@ -94,10 +95,10 @@ t.buildrtyper(type_system="ootype").specialize() self.graph = t.graphs[0] - if conftest.option.view: + if option.view: t.viewcg() - if conftest.option.wd: + if option.wd: tmpdir = py.path.local('.') else: tmpdir = udir @@ -119,7 +120,7 @@ def _build_exe(self): tmpfile = self._gen.generate_source() - if conftest.option.source: + if option.source: return None self.__check_helper("ilasm") From pedronis at codespeak.net Sat Mar 25 22:01:27 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Mar 2006 22:01:27 +0100 (CET) Subject: [pypy-svn] r25003 - pypy/dist/pypy/rpython/memory/test Message-ID: <20060325210127.D0DD610095@code0.codespeak.net> Author: pedronis Date: Sat Mar 25 22:01:26 2006 New Revision: 25003 Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py Log: repair test to match changes. Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Sat Mar 25 22:01:26 2006 @@ -345,8 +345,9 @@ t, transformer = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False) graph = graphof(t, f) ops = getops(graph) - assert len(ops['getfield']) == 2 - assert len(ops['setfield']) == 4 + assert len(ops['bare_getfield']) == 2 + assert len(ops['bare_setfield']) == 2 + assert len(ops['setfield']) == 2 def test_arraybarrier(): S = lltype.GcStruct("S", ('x', lltype.Signed)) @@ -413,7 +414,7 @@ dgraph, t = make_deallocator(S) ops = getops(dgraph) assert len(ops['direct_call']) == 2 - assert len(ops['getfield']) == 2 + assert len(ops['bare_getfield']) == 2 assert len(ops['gc_free']) == 1 def test_deallocator_array(): @@ -426,7 +427,7 @@ dgraph, t = make_deallocator(S) ops = getops(dgraph) assert len(ops['direct_call']) == 4 - assert len(ops['getfield']) == 4 + assert len(ops['bare_getfield']) == 4 assert len(ops['getarraysubstruct']) == 1 assert len(ops['gc_free']) == 1 From nik at codespeak.net Sat Mar 25 23:02:47 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Sat, 25 Mar 2006 23:02:47 +0100 (CET) Subject: [pypy-svn] r25004 - in pypy/dist/pypy/translator/squeak: . test Message-ID: <20060325220247.F0A7C100B6@code0.codespeak.net> Author: nik Date: Sat Mar 25 23:02:46 2006 New Revision: 25004 Modified: pypy/dist/pypy/translator/squeak/opformatter.py pypy/dist/pypy/translator/squeak/test/test_llops.py Log: fix gensqueak after div/truediv/floordiv cleanup. Modified: pypy/dist/pypy/translator/squeak/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/squeak/opformatter.py (original) +++ pypy/dist/pypy/translator/squeak/opformatter.py Sat Mar 25 23:02:46 2006 @@ -33,7 +33,6 @@ 'bool_not': 'not', 'cast_int_to_float': 'asFloat', - 'float_div': '/', # overrides the div definition in number_ops 'float_fmod': r'\\', # we can't really distinguish mod and fmod 'float_floor': 'floor', # XXX this potentially incorrect (may return LargeIntegers) @@ -50,7 +49,6 @@ 'sub': '-', 'eq': '=', 'mul': '*', - 'div': '//', 'floordiv': '//', 'truediv': '/ asFloat', 'mod': r'\\', Modified: pypy/dist/pypy/translator/squeak/test/test_llops.py ============================================================================== --- pypy/dist/pypy/translator/squeak/test/test_llops.py (original) +++ pypy/dist/pypy/translator/squeak/test/test_llops.py Sat Mar 25 23:02:46 2006 @@ -58,10 +58,8 @@ ("add", Signed, 1, 2), ("sub", Signed, 1, 3), ("mul", Signed, 2, 3), - ("div", Signed, 7, 3), ("floordiv", Signed, 7, 3), # XXX what about division by zero? ("floordiv", Signed, -7, 3), - ("truediv", Float, 7, 4), ("mod", Signed, 9, 4), ("mod", Signed, 9, -4), ("eq", Bool, 1, 1), @@ -135,8 +133,7 @@ llfunctest(istrue, ()) def test_floatoperations_binary(): - for llopname in "add", "sub", "mul", "div", "mod", "fmod", \ - "floordiv", "truediv": + for llopname in "add", "sub", "mul", "mod", "fmod", "truediv": exec """def lloptest(i): f = llop.cast_int_to_float(Float, i) return llop.float_%s(Float, f, 1.25)""" % llopname From hpk at codespeak.net Sat Mar 25 23:31:26 2006 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 25 Mar 2006 23:31:26 +0100 (CET) Subject: [pypy-svn] r25005 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060325223126.98D5110087@code0.codespeak.net> Author: hpk Date: Sat Mar 25 23:31:15 2006 New Revision: 25005 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: my departure date will only become clear when i am there i guess Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Sat Mar 25 23:31:15 2006 @@ -12,7 +12,7 @@ Name Arrive/Depart Accomodation ==================== ============== ===================== Anders Chrigstroem 30/3 - 10/4 Ermina -Holger Krekel 1st - 14 Ermina +Holger Krekel 1st - (10-14) Ermina Samuele Pedroni 30/3 - 10/4 Ermina Armin Rigo -- private Christian Tismer ? Ermina? From bea at codespeak.net Sun Mar 26 14:54:39 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Sun, 26 Mar 2006 14:54:39 +0200 (CEST) Subject: [pypy-svn] r25014 - pypy/extradoc/planning Message-ID: <20060326125439.DC67810087@code0.codespeak.net> Author: bea Date: Sun Mar 26 14:54:36 2006 New Revision: 25014 Modified: pypy/extradoc/planning/conference-planning.txt Log: Updated with acceptance for XP 2006, Agile 2006 (Bea), updated status of OOPSLA and updated with Holgers suggestion of Middleware - deadline 3rd April Modified: pypy/extradoc/planning/conference-planning.txt ============================================================================== --- pypy/extradoc/planning/conference-planning.txt (original) +++ pypy/extradoc/planning/conference-planning.txt Sun Mar 26 14:54:36 2006 @@ -65,16 +65,6 @@ Due: sprint planning, possibly inviting Ka Ping (regarding E-lang) -FOSDEM 2006 ------------- -The sixth meeting of Free and Open Source European Developers meeting. -Time & location: 25th-26th of February, 2006, Brussels - -A conference to attend - maybe for those not participating at PyCon? - -http://www.fosdem.org/2006/ - -No papers submitted - attendance? Calibre workshop ----------------- @@ -86,6 +76,14 @@ www.calibre.ie No papers submitted - Bea will attend. +( Bea didnt attend - Jacob did). + +XP France: +-------------- +24-25th March? Nicholas? + +Logilab attended and did a talk. + ACCU 2006 ---------- @@ -99,6 +97,7 @@ http://www.accu.org/conference/ No papers submitted - attendance - Michael H, Jacob? +Michael will do a talk there about PyPy. XP 2006 ----------- @@ -109,7 +108,7 @@ Call for papers: Submission date: 30th of January 2006 -(Bea plan to submit an experience report) +Experience report accepted - Bea will go and present. http://virtual.vtt.fi/virtual/xp2006/sivu1.html @@ -128,9 +127,8 @@ Time and location: 23-28th of July 2006, Minneapolis, Minnesota, USA -Change Maker (Bea) will plan to submit: -- experience report -- research paper +Experience report proposal accepted - Bea will submit the report +(first draft 14th April, final draft 30th April) and go there. OOPSLA 2006 ------------ @@ -146,4 +144,19 @@ http://www.oopsla.org/2006/ -Samuele and Armin plan to submit paper and attend. \ No newline at end of file +Samuele and Armin plan to submit paper and attend. + +No paper submitted - attendance (workshop dynamic languages)? + +MIDDLEWARE 2006 +------------------------- +DEADLINE: 3rd April 2006/scientific papers + +Time & location: November 27 - December 1, MELBOURNE, AUSTRALIA + + http://2006.middleware-conference.org/ + +ACM/IFIP/USENIX 7th International Middleware Conference + "Novel development paradigms, APIs, and languages"/PyPy? + + Suggestion by Holger. Submission/attendance? From cfbolz at codespeak.net Sun Mar 26 16:10:48 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 26 Mar 2006 16:10:48 +0200 (CEST) Subject: [pypy-svn] r25015 - pypy/dist/pypy/translator/backendopt Message-ID: <20060326141048.594311009D@code0.codespeak.net> Author: cfbolz Date: Sun Mar 26 16:10:46 2006 New Revision: 25015 Added: pypy/dist/pypy/translator/backendopt/stat.py Modified: pypy/dist/pypy/translator/backendopt/all.py Log: some minimal (and by default disable) statistic printing Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Sun Mar 26 16:10:46 2006 @@ -4,11 +4,14 @@ from pypy.translator.backendopt.malloc import remove_simple_mallocs from pypy.translator.backendopt.ssa import SSI_to_SSA from pypy.translator.backendopt.propagate import propagate_all +from pypy.translator.backendopt.stat import print_statistics from pypy.translator.backendopt.merge_if_blocks import merge_if_blocks from pypy.translator import simplify from pypy.translator.backendopt.escape import malloc_to_stack from pypy.translator.backendopt.support import log +PRINT_STATISTICS = False + def backend_optimizations(translator, raisingop2direct_call_all=False, inline_threshold=1, mallocs=True, @@ -17,6 +20,10 @@ propagate=False, heap2stack=False): + if PRINT_STATISTICS: + print "before optimizations:" + print_statistics(translator.graphs[0], translator) + if raisingop2direct_call_all: raisingop2direct_call(translator) @@ -26,6 +33,10 @@ simplify.eliminate_empty_blocks(graph) simplify.transform_dead_op_vars(graph, translator) + if PRINT_STATISTICS: + print "after no-op removal:" + print_statistics(translator.graphs[0], translator) + # ... if propagate: propagate_all(translator) @@ -34,6 +45,10 @@ if inline_threshold: auto_inlining(translator, inline_threshold) + if PRINT_STATISTICS: + print "after inlining:" + print_statistics(translator.graphs[0], translator) + # vaporize mallocs if mallocs: tot = 0 @@ -46,6 +61,11 @@ simplify.transform_dead_op_vars(graph, translator) tot += count log.malloc("removed %d simple mallocs in total" % tot) + + if PRINT_STATISTICS: + print "after malloc removal:" + print_statistics(translator.graphs[0], translator) + if propagate: propagate_all(translator) @@ -55,7 +75,11 @@ if merge_if_blocks_to_switch: for graph in translator.graphs: merge_if_blocks(graph) - + + if PRINT_STATISTICS: + print "after if-to-switch:" + print_statistics(translator.graphs[0], translator) + if ssa_form: for graph in translator.graphs: SSI_to_SSA(graph) Added: pypy/dist/pypy/translator/backendopt/stat.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/backendopt/stat.py Sun Mar 26 16:10:46 2006 @@ -0,0 +1,33 @@ +from pypy.translator.simplify import get_graph + +def get_statistics(graph, translator): + seen_graphs = {} + stack = [graph] + num_graphs = 0 + num_blocks = 0 + num_ops = 0 + while stack: + graph = stack.pop() + if graph in seen_graphs: + continue + seen_graphs[graph] = True + num_graphs += 1 + for block in graph.iterblocks(): + num_blocks += 1 + for op in block.operations: + if op.opname == "direct_call": + called_graph = get_graph(op.args[0], translator) + if called_graph is not None: + stack.append(called_graph) + elif op.opname == "indirect_call": + called_graphs = op.args[-1].value + if called_graphs is not None: + stack.extend(called_graphs) + num_ops += 1 + return num_graphs, num_blocks, num_ops + +def print_statistics(graph, translator): + num_graphs, num_blocks, num_ops = get_statistics(graph, translator) + print ("Statistics:\nnumber of graphs %s\n" + "number of blocks %s\n" + "number of operations %s\n") % (num_graphs, num_blocks, num_ops) From arigo at codespeak.net Mon Mar 27 11:46:00 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 11:46:00 +0200 (CEST) Subject: [pypy-svn] r25022 - pypy/dist/pypy/rpython Message-ID: <20060327094600.3765B10088@code0.codespeak.net> Author: arigo Date: Mon Mar 27 11:45:59 2006 New Revision: 25022 Modified: pypy/dist/pypy/rpython/typesystem.py Log: Missing import. (the diff is misleading: the real reason for this change is that TyperError is used directly at several other places.) Modified: pypy/dist/pypy/rpython/typesystem.py ============================================================================== --- pypy/dist/pypy/rpython/typesystem.py (original) +++ pypy/dist/pypy/rpython/typesystem.py Mon Mar 27 11:45:59 2006 @@ -5,7 +5,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.lltypesystem import lltype -from pypy.rpython import error +from pypy.rpython.error import TyperError class TypeSystem(object): __metaclass__ = extendabletype @@ -132,7 +132,7 @@ not isinstance(robj2.lowleveltype, ootype.Instance)) and \ (robj1.lowleveltype is not ootype.Class or robj2.lowleveltype is not ootype.Class): - raise error.TyperError('is of instances of the non-instances: %r, %r' % ( + raise TyperError('is of instances of the non-instances: %r, %r' % ( roriginal1, roriginal2)) v_list = hop.inputargs(robj1, robj2) From arigo at codespeak.net Mon Mar 27 12:30:32 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 12:30:32 +0200 (CEST) Subject: [pypy-svn] r25023 - pypy/dist/pypy/rpython Message-ID: <20060327103032.05F4710086@code0.codespeak.net> Author: arigo Date: Mon Mar 27 12:30:26 2006 New Revision: 25023 Modified: pypy/dist/pypy/rpython/llinterp.py Log: Remove the last reference to lladdress in the llinterp. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Mon Mar 27 12:30:26 2006 @@ -1,7 +1,6 @@ from pypy.objspace.flow.model import FunctionGraph, Constant, Variable, c_last_exception from pypy.rpython.rarithmetic import intmask, r_uint, ovfcheck, r_longlong, r_ulonglong from pypy.rpython.lltypesystem import lltype, llmemory, lloperation -from pypy.rpython.memory import lladdress from pypy.rpython.ootypesystem import ootype import sys @@ -679,8 +678,8 @@ ("gt", ">"), ("ge", ">=")): exec py.code.Source(""" def op_adr_%s(self, addr1, addr2): - assert isinstance(addr1, lladdress.address) - assert isinstance(addr2, lladdress.address) + checkadr(addr1) + checkadr(addr2) return addr1 %s addr2""" % (opname, op)).compile() # __________________________________________________________ From arigo at codespeak.net Mon Mar 27 12:30:53 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 12:30:53 +0200 (CEST) Subject: [pypy-svn] r25024 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060327103053.E0D5810086@code0.codespeak.net> Author: arigo Date: Mon Mar 27 12:30:53 2006 New Revision: 25024 Modified: pypy/dist/pypy/translator/cli/ (props changed) pypy/dist/pypy/translator/cli/test/ (props changed) Log: fixeol From arigo at codespeak.net Mon Mar 27 13:50:10 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 13:50:10 +0200 (CEST) Subject: [pypy-svn] r25025 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20060327115010.42EA410078@code0.codespeak.net> Author: arigo Date: Mon Mar 27 13:50:07 2006 New Revision: 25025 Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py pypy/dist/pypy/rpython/lltypesystem/rpbc.py pypy/dist/pypy/rpython/ootypesystem/rpbc.py pypy/dist/pypy/rpython/rmodel.py pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: Pass test_disjoint_pbcs. The repr of SomePBC is a (breath here) MultipleUnrelatedFrozenPBCRepr for frozen PBCs with no common attribute access set. This is an Address in the lltypesystem, and an instance of the empty base PBCROOT class in the ootypesystem. Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/llmemory.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py Mon Mar 27 13:50:07 2006 @@ -130,6 +130,15 @@ self.ob = ob self.offset = offset + def __repr__(self): + if self.ob is None: + s = 'NULL' + else: + s = str(self.ob) + if self.offset is not None: + s = '%s + %r' % (s, self.offset) + return '' % (s,) + def __add__(self, other): if isinstance(other, AddressOffset): if self.offset is None: Modified: pypy/dist/pypy/rpython/lltypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rpbc.py Mon Mar 27 13:50:07 2006 @@ -11,18 +11,24 @@ commonbase, allattributenames, adjust_shape, \ AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr, \ AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ - AbstractFunctionsPBCRepr -from pypy.rpython.lltypesystem import rclass + AbstractFunctionsPBCRepr, AbstractMultipleUnrelatedFrozenPBCRepr, \ + SingleFrozenPBCRepr +from pypy.rpython.lltypesystem import rclass, llmemory from pypy.tool.sourcetools import has_varargs from pypy.rpython import callparse def rtype_is_None(robj1, rnone2, hop, pos=0): - if not isinstance(robj1.lowleveltype, Ptr): - raise TyperError('is None of instance of the non-pointer: %r' % (robj1)) - v1 = hop.inputarg(robj1, pos) - return hop.genop('ptr_iszero', [v1], resulttype=Bool) - + if isinstance(robj1.lowleveltype, Ptr): + v1 = hop.inputarg(robj1, pos) + return hop.genop('ptr_iszero', [v1], resulttype=Bool) + elif robj1.lowleveltype == llmemory.Address: + v1 = hop.inputarg(robj1, pos) + cnull = hop.inputconst(llmemory.Address, robj1.null_instance()) + return hop.genop('adr_eq', [v1, cnull], resulttype=Bool) + else: + raise TyperError('rtype_is_None of %r' % (robj1)) + # ____________________________________________________________ class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr): @@ -50,6 +56,42 @@ return llops.genop('getfield', [vpbc, cmangledname], resulttype = r_value) + +class MultipleUnrelatedFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr): + """Representation selected for multiple non-callable pre-built constants + with no common access set.""" + + lowleveltype = llmemory.Address + EMPTY = Struct('pbc') + + def convert_pbc(self, pbcptr): + return llmemory.fakeaddress(pbcptr) + + def create_instance(self): + return malloc(self.EMPTY, immortal=True) + + def null_instance(self): + return llmemory.Address._defl() + +class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr, + MultipleUnrelatedFrozenPBCRepr), + pairtype(MultipleUnrelatedFrozenPBCRepr, + SingleFrozenPBCRepr), + pairtype(SingleFrozenPBCRepr, + MultipleUnrelatedFrozenPBCRepr)): + def rtype_is_((robj1, robj2), hop): + if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr): + r = robj1 + else: + r = robj2 + vlist = hop.inputargs(r, r) + return hop.genop('adr_eq', vlist, resulttype=Bool) + +class __extend__(pairtype(MultipleFrozenPBCRepr, + MultipleUnrelatedFrozenPBCRepr)): + def convert_from_to((robj1, robj2), v, llops): + return llops.genop('cast_ptr_to_adr', [v], resulttype=llmemory.Address) + # ____________________________________________________________ class FunctionsPBCRepr(AbstractFunctionsPBCRepr): Modified: pypy/dist/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rpbc.py Mon Mar 27 13:50:07 2006 @@ -1,7 +1,7 @@ from pypy.rpython.rmodel import CanBeNull, Repr, inputconst from pypy.rpython.rpbc import AbstractClassesPBCRepr, AbstractMethodsPBCRepr, \ AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \ - AbstractFunctionsPBCRepr + AbstractFunctionsPBCRepr, AbstractMultipleUnrelatedFrozenPBCRepr from pypy.rpython.rclass import rtype_new_instance, getinstancerepr from pypy.rpython.rpbc import get_concrete_calltable from pypy.rpython import callparse @@ -14,6 +14,13 @@ import types +def rtype_is_None(robj1, rnone2, hop, pos=0): + v1 = hop.inputarg(robj1, pos) + v2 = hop.genop('oononnull', [v1], resulttype=ootype.Bool) + v3 = hop.genop('bool_not', [v2], resulttype=ootype.Bool) + return v3 + + class FunctionsPBCRepr(AbstractFunctionsPBCRepr): """Representation selected for a PBC of function(s).""" @@ -160,12 +167,16 @@ def convert_from_to(_, v, llops): return v +# ____________________________________________________________ + +PBCROOT = ootype.Instance('pbcroot', ootype.ROOT) + class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr): """Representation selected for multiple non-callable pre-built constants.""" def __init__(self, rtyper, access_set): self.rtyper = rtyper self.access_set = access_set - self.lowleveltype = ootype.Instance('pbc', ootype.ROOT) + self.lowleveltype = ootype.Instance('pbc', PBCROOT) self.pbc_cache = {} def _setup_repr(self): @@ -184,4 +195,24 @@ return llops.genop('oogetfield', [vpbc, cmangledname], resulttype = r_value) +class MultipleUnrelatedFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr): + """Representation selected for multiple non-callable pre-built constants + with no common access set.""" + + lowleveltype = PBCROOT + + def convert_pbc(self, pbc): + if ootype.typeOf(pbc) != PBCROOT: + pbc = ootype.ooupcast(PBCROOT, pbc) + return pbc + + def create_instance(self): + return ootype.new(PBCROOT) + + def null_instance(self): + return ootype.null(PBCROOT) +class __extend__(pairtype(MultipleFrozenPBCRepr, + MultipleUnrelatedFrozenPBCRepr)): + def convert_from_to((robj1, robj2), v, llops): + return llops.genop('ooupcast', [v], resulttype=PBCROOT) Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Mon Mar 27 13:50:07 2006 @@ -120,7 +120,7 @@ if self.lowleveltype is not Void: try: realtype = typeOf(value) - except (AssertionError, AttributeError): + except (AssertionError, AttributeError, TypeError): realtype = '???' if realtype != self.lowleveltype: raise TyperError("convert_const(self = %r, value = %r)" % ( Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Mon Mar 27 13:50:07 2006 @@ -349,7 +349,14 @@ access = descs[0].queryattrfamily() for desc in descs[1:]: access1 = desc.queryattrfamily() - assert access1 is access # XXX not implemented + if access1 is not access: + try: + return rtyper.pbc_reprs['unrelated'] + except KeyError: + rpbc = rtyper.type_system.rpbc + result = rpbc.MultipleUnrelatedFrozenPBCRepr(rtyper) + rtyper.pbc_reprs['unrelated'] = result + return result try: return rtyper.pbc_reprs[access] except KeyError: @@ -377,7 +384,39 @@ return object() # lowleveltype is Void -class AbstractMultipleFrozenPBCRepr(CanBeNull, Repr): +class AbstractMultipleUnrelatedFrozenPBCRepr(CanBeNull, Repr): + """For a SomePBC of frozen PBCs that have no common access set. + The only possible operation on such a thing is comparison with 'is'.""" + + def __init__(self, rtyper): + self.rtyper = rtyper + self.converted_pbc_cache = {} + + def convert_desc(self, frozendesc): + try: + return self.converted_pbc_cache[frozendesc] + except KeyError: + r = self.rtyper.getrepr(annmodel.SomePBC([frozendesc])) + if r.lowleveltype is Void: + # must create a new empty structure, as a placeholder + pbc = self.create_instance() + else: + pbc = r.convert_desc(frozendesc) + convpbc = self.convert_pbc(pbc) + self.converted_pbc_cache[frozendesc] = convpbc + return convpbc + + def convert_const(self, pbc): + if pbc is None: + return self.null_instance() + if isinstance(pbc, types.MethodType) and pbc.im_self is None: + value = pbc.im_func # unbound method -> bare function + frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc) + return self.convert_desc(frozendesc) + + +class AbstractMultipleFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr): + """For a SomePBC of frozen PBCs with a common attribute access set.""" def _setup_repr_fields(self): fields = [] @@ -415,14 +454,6 @@ setattr(result, mangled_name, llvalue) return result - def convert_const(self, pbc): - if pbc is None: - return self.null_instance() - if isinstance(pbc, types.MethodType) and pbc.im_self is None: - value = pbc.im_func # unbound method -> bare function - frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc) - return self.convert_desc(frozendesc) - def rtype_getattr(self, hop): attr = hop.args_s[1].const vpbc, vattr = hop.inputargs(self, Void) Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Mon Mar 27 13:50:07 2006 @@ -1094,6 +1094,62 @@ res = interpret(f, [i, 1234], type_system=self.ts) assert res == f(i, 1234) + def test_disjoint_pbcs(self): + class Frozen(object): + def __init__(self, v): + self.v = v + def _freeze_(self): + return True + + fr1 = Frozen(2) + fr2 = Frozen(3) + + def g1(x): + return x.v + def g2(y): + return y.v + def h(x): + return x is not None + def h2(x): + return x is fr1 + + def f(): + a = g1(fr1) + b = g2(fr2) + h(None) + return (h(fr1) + 10*h(fr2) + 100*a + 1000*b + + 10000*h2(fr1) + 100000*h2(fr2)) + + res = interpret(f, [], type_system=self.ts) + assert res == 13211 + + def test_disjoint_pbcs_2(self): + class Frozen(object): + def __init__(self, v): + self.v = v + def _freeze_(self): + return True + fr1 = Frozen(1) + fr2 = Frozen(2) + fr3 = Frozen(3) + def getv(x): + return x.v + def h(x): + return (x is not None) + 2*(x is fr2) + 3*(x is fr3) + def f(n): + if n == 1: + fr = fr1 + else: + fr = fr2 + total = getv(fr) + if n == 3: + fr = fr3 + h(None) + return total + 10*h(fr) + + res = interpret(f, [3], type_system=self.ts) + assert res == 42 + def test_call_from_list(): # Don't test with ootype, since it doesn't support lists in a @@ -1363,33 +1419,6 @@ res = interp.eval_graph(ll_h_graph, [None, c_f, c_a]) assert typeOf(res) == A_repr.lowleveltype -def test_disjoint_pbcs(): - py.test.skip("in-progress") - class Frozen(object): - def __init__(self, v): - self.v = 2 - def _freeze_(self): - return True - - f1 = Frozen(2) - f2 = Frozen(3) - - def g1(x): - return x.v - def g2(y): - return y.v - def h(x): - return x != None - - def f(): - a = g1(f1) - b = g2(f2) - return h(f1)+h(f2)+a+b - - res = interpret(f, []) - - assert res == 7 - class TestLltype(BaseTestRPBC): ts = "lltype" From arigo at codespeak.net Mon Mar 27 13:51:08 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 13:51:08 +0200 (CEST) Subject: [pypy-svn] r25026 - pypy/dist/pypy/jit/test Message-ID: <20060327115108.EE26910086@code0.codespeak.net> Author: arigo Date: Mon Mar 27 13:51:08 2006 New Revision: 25026 Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py Log: This JIT test passes again now. Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Mon Mar 27 13:51:08 2006 @@ -260,7 +260,6 @@ 'int_sub': 1} def test_simple_struct(): - py.test.skip("pending rpython.test_rpbc.test_disjoint_pbcs") S = lltype.GcStruct('helloworld', ('hello', lltype.Signed), ('world', lltype.Signed), hints={'immutable': True}) From auc at codespeak.net Mon Mar 27 13:55:27 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Mon, 27 Mar 2006 13:55:27 +0200 (CEST) Subject: [pypy-svn] r25027 - in pypy/dist/pypy/objspace: . test Message-ID: <20060327115527.C709710086@code0.codespeak.net> Author: auc Date: Mon Mar 27 13:55:25 2006 New Revision: 25027 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: fix wait_needed Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Mon Mar 27 13:55:25 2006 @@ -159,8 +159,8 @@ class W_Var(baseobjspace.W_Root, object): def __init__(w_self): - w_self.w_bound_to = w_self # FIXME : making this a ring asap - w_self.w_needed = False # is it needed ... ? + w_self.w_bound_to = w_self + w_self.w_needed = False def __repr__(w_self): if w_self.w_bound_to: @@ -187,7 +187,9 @@ w_self.w_needed = True for w_alias in aliases(space, w_self): need_waiters = schedule_state.pop_blocked_byneed_on(w_alias) + w_alias.w_needed = True for waiter in need_waiters: + print " :byneed waiter", waiter, "awaken on", w_alias schedule_state.add_to_runnable(waiter) # set curr thread to blocked, switch to runnable thread current = get_current_coroutine() @@ -362,7 +364,7 @@ if isinstance(w_obj, W_Var): if space.is_true(is_bound(space, w_var)): if space.is_true(is_bound(space, w_obj)): - return unify(space, #FIXME, should be unify bizness + return unify(space, deref(space, w_var), deref(space, w_obj)) return _assign(space, w_obj, deref(space, w_var)) @@ -373,7 +375,9 @@ else: # 3. w_obj is a value if space.is_true(is_free(space, w_var)): return _assign(space, w_var, w_obj) - return unify(space, deref(space, w_var), w_obj) + # should not be reachable as of 27-03-2006 + raise OperationError(space.w_RuntimeError, + space.wrap("Unreachable code in bind")) app_bind = gateway.interp2app(bind) def _assign(space, w_var, w_val): @@ -446,6 +450,8 @@ return unify(space, w_y, w_x) elif not isinstance(w_y, W_Var): # x var, y value + if space.is_true(is_bound(space, w_x)): + return unify(space, deref(space, w_x), w_y) return bind(space, w_x, w_y) # x, y are vars elif space.is_true(is_bound(space, w_x)) and \ @@ -473,7 +479,7 @@ return bind(space, w_x, w_y) def _unify_values(space, w_v1, w_v2): - print " :unify values", w_v1, w_v2 + #print " :unify values", w_v1, w_v2 # unify object of the same type ... FIXME if not space.is_w(space.type(w_v1), space.type(w_v2)): @@ -489,7 +495,7 @@ return space.w_None def _unify_iterables(space, w_i1, w_i2): - print " :unify iterables", w_i1, w_i2 + #print " :unify iterables", w_i1, w_i2 # assert lengths if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): fail(space, w_i1, w_i2) Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Mon Mar 27 13:55:25 2006 @@ -233,6 +233,7 @@ def lsum(L, a, limit): """this summer controls the generator""" if limit > 0: + print "sum : ", a Head, Tail = newvar(), newvar() print "-- sum waiting on L" wait(L) @@ -245,8 +246,10 @@ print "before" Y = newvar() T = newvar() + disp(Y) + disp(T) uthread(lgenerate, 0, Y) - unify(T, uthread(lsum, Y, 0, 3)) + unify(T, uthread(lsum, Y, 0, 10)) print "after" wait(T) From arigo at codespeak.net Mon Mar 27 13:59:39 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 13:59:39 +0200 (CEST) Subject: [pypy-svn] r25028 - pypy/dist/pypy/rpython/ootypesystem Message-ID: <20060327115939.A16FA10086@code0.codespeak.net> Author: arigo Date: Mon Mar 27 13:59:38 2006 New Revision: 25028 Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py Log: Some useful __repr__. Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Mon Mar 27 13:59:38 2006 @@ -2,6 +2,7 @@ from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \ Primitive, isCompatibleType, enforce from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType +from pypy.tool.uid import uid STATICNESS = True @@ -182,7 +183,13 @@ def __init__(self, INSTANCE): self.__dict__["_TYPE"] = INSTANCE INSTANCE._init_instance(self) - + + def __repr__(self): + return '<%s>' % (self,) + + def __str__(self): + return '%r inst at 0x%x' % (self._TYPE._name, uid(self)) + def __getattr__(self, name): DEFINST, meth = self._TYPE._lookup(name) if meth is not None: @@ -244,6 +251,9 @@ def __init__(self, INSTANCE): self.__dict__["_TYPE"] = INSTANCE + def __str__(self): + return '%r null inst' % (self._TYPE._name,) + def __getattribute__(self, name): if name.startswith("_"): return object.__getattribute__(self, name) @@ -274,6 +284,12 @@ assert isSubclass(inst._TYPE, INSTANCE) self.__dict__['_inst'] = inst + def __repr__(self): + if self._TYPE == self._inst._TYPE: + return repr(self._inst) + else: + return '<%r view of %s>' % (self._TYPE._name, self._inst) + def __ne__(self, other): return not (self == other) From ericvrp at codespeak.net Mon Mar 27 14:45:21 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Mon, 27 Mar 2006 14:45:21 +0200 (CEST) Subject: [pypy-svn] r25031 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20060327124521.6823910085@code0.codespeak.net> Author: ericvrp Date: Mon Mar 27 14:45:20 2006 New Revision: 25031 Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Added function replacement to pyllvm. Added display of generated JIT code. Added delete function. Modified: pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/pyllvm.cpp Mon Mar 27 14:45:20 2006 @@ -14,6 +14,10 @@ #include "llvm/Analysis/Verifier.h" #include "llvm/DerivedTypes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + + // c++ includes #include #include @@ -61,26 +65,41 @@ // parse and verify llcode try { + Module *M = &self->exec->getModule(); + if (fnname) { - // XXX ParseAssemblyString(llcode, &self->exec->getModule()); //redefinition - /*Module* M =*/ ParseAssemblyString(llcode, NULL); - Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname)); - if (fn == NULL) { + Function *F = M->getNamedFunction(fnname); + if (F == NULL) { PyErr_SetString(PyExc_Exception, "Failed to resolve function to be replaced"); return NULL; } - self->exec->recompileAndRelinkFunction(fn); - - // TODO replace fn with whatever ParseAssemblyString made of llcode - - PyErr_SetString(PyExc_Exception, "function replacing not supported yet"); - return NULL; - + F->setName(""); // now it won't conflicht + ParseAssemblyString(llcode, M); + Function *Fnew = M->getNamedFunction(fnname); + F->replaceAllUsesWith(Fnew); // Everything using the old one uses the new one + self->exec->freeMachineCodeForFunction(F); // still no-op on march 27th 2006 + F->eraseFromParent(); // also, take it out of the JIT (LLVM IR) if it was in it + + /* + XXX this is a really dump implementation!!! Should really be somehthing like... + codegend_uses = list of function that have codegen'd calls to F + for func in codegend_uses: + self->exec->recompileAndRelinkFunction(func); + // what about (codegen-ed) pointers to F? + */ + Module::FunctionListType &fns = M->getFunctionList(); + for (Module::FunctionListType::iterator ii = fns.begin(); + ii != fns.end(); + ++ii) { + if (!(ii->isIntrinsic() || ii->isExternal())) { + self->exec->recompileAndRelinkFunction(ii); + } + } } else { - ParseAssemblyString(llcode, &self->exec->getModule()); + ParseAssemblyString(llcode, M); } - verifyModule(self->exec->getModule(), ThrowExceptionAction); + verifyModule(*M, ThrowExceptionAction); // XXX make this optional for performance? Py_INCREF(Py_None); return Py_None; @@ -193,9 +212,9 @@ char *fnname = PyString_AsString(pyfnname); try { - Function *fn = self->exec->getModule().getNamedFunction(std::string(fnname)); + Function *fn = self->exec->getModule().getNamedFunction(fnname); if (fn == NULL) { - PyErr_SetString(PyExc_Exception, "Failed to resolve function"); + PyErr_SetString(PyExc_Exception, "Failed to resolve function to call"); return NULL; } @@ -223,6 +242,39 @@ } } +static PyObject *ee_delete(PyExecutionEngine *self, PyObject *args) { + + if (PyTuple_Size(args) != 1) { + PyErr_SetString(PyExc_TypeError, "missing functionname"); + return NULL; + } + + PyObject *pyfnname = PyTuple_GetItem(args, 0); + if (!PyString_Check(pyfnname)) { + PyErr_SetString(PyExc_TypeError, "functionname expected as string"); + return NULL; + } + char *fnname = PyString_AsString(pyfnname); + + try { + Function *fn = self->exec->getModule().getNamedFunction(fnname); + if (fn == NULL) { + PyErr_SetString(PyExc_Exception, "Failed to resolve function to delete"); + return NULL; + } + + // XXX fn should not be refered to from anywhere! Check for this? + self->exec->freeMachineCodeForFunction(fn); // still no-op on march 27th 2006 + fn->eraseFromParent(); + } catch (...) { + PyErr_SetString(PyExc_Exception, "Unexpected unknown exception occurred"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + static PyObject *ee_functions(PyExecutionEngine *self) { int funccount = 0; Module::FunctionListType &fns = self->exec->getModule().getFunctionList(); @@ -267,9 +319,10 @@ } static PyMethodDef ee_methodlist[] = { - {"parse", (PyCFunction) ee_parse, METH_VARARGS, NULL}, - {"functions", (PyCFunction) ee_functions, METH_NOARGS, NULL}, - {"call", (PyCFunction) ee_call, METH_VARARGS, NULL}, + {"parse" , (PyCFunction) ee_parse , METH_VARARGS, NULL}, + {"call" , (PyCFunction) ee_call , METH_VARARGS, NULL}, + {"delete" , (PyCFunction) ee_delete , METH_VARARGS, NULL}, + {"functions", (PyCFunction) ee_functions, METH_NOARGS , NULL}, {NULL, NULL} }; @@ -380,9 +433,17 @@ return Py_None; } +static PyObject *pyllvm_toggle_print_machineinstrs(PyObject *self, PyObject *args) { + PrintMachineCode = !PrintMachineCode; + + Py_INCREF(Py_None); + return Py_None; +} + PyMethodDef pyllvm_functions[] = { - {"get_ee", pyllvm_get_ee, METH_NOARGS, NULL}, - {"delete_ee", pyllvm_delete_ee, METH_NOARGS, NULL}, + {"get_ee" , pyllvm_get_ee , METH_NOARGS, NULL}, + {"delete_ee" , pyllvm_delete_ee , METH_NOARGS, NULL}, + {"toggle_print_machineinstrs", pyllvm_toggle_print_machineinstrs, METH_NOARGS, NULL}, {NULL, NULL} }; @@ -402,6 +463,11 @@ PyModule_AddObject(module, "ExecutionEngine", (PyObject*) &ExecutionEngine_Type); + if (0) { // pass in `lli` type parameters + static char * Args[] = { "", "-print-machineinstrs", 0 }; + int n_args = 2; + cl::ParseCommandLineOptions(n_args, Args); + } } } Modified: pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Mon Mar 27 14:45:20 2006 @@ -82,12 +82,11 @@ """similar to test_call_between_parsed_code with additional complexity because we rebind the add1 function to another version after it the first version already has been used.""" - py.test.skip("function replacement support in progress") ee = get_fresh_ee() ee.parse(ll_snippet.calc) ee.parse(ll_snippet.add1) assert ee.call("add1", 41) == 42 - assert ee.call("calc", 122) == 123 + assert ee.call("calc", 122) == 123 #XXX need recompileAndRelinkFunction somewhere ee.parse(ll_snippet.add1_version2, "add1") assert ee.call("add1", 42) == 142 assert ee.call("calc", 142) == 242 @@ -102,11 +101,30 @@ assert ee.call("add1_to_global_int_a") == 92 assert ee.call("sub10_from_global_int_a") == 82 -def TODOtest_native_code(): #examine JIT generate native (assembly) code - pass +def test_native_code(): #examine JIT generate native (assembly) code + pyllvm.toggle_print_machineinstrs() + ee = get_fresh_ee() + ee.parse(ll_snippet.calc) + ee.parse(ll_snippet.add1) + assert ee.call("calc", 41) == 42 + pyllvm.toggle_print_machineinstrs() -def TODOtest_delete_function(): - pass +def test_delete_function(): #this will only work if nothing uses Fn of course! + ee = get_fresh_ee() + ee.parse(ll_snippet.calc) + ee.parse(ll_snippet.add1) + assert len(ee.functions()) == 2 + + ee.delete("calc") + assert len(ee.functions()) == 1 + assert ee.call("add1", 41) == 42 + + ee.delete("add1") + assert len(ee.functions()) == 0 + + ee.parse(ll_snippet.calc) + ee.parse(ll_snippet.add1) + assert ee.call("calc", 100) == 101 def TODOtest_add_to_function(): pass From arigo at codespeak.net Mon Mar 27 14:52:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 14:52:06 +0200 (CEST) Subject: [pypy-svn] r25032 - pypy/dist/pypy/jit Message-ID: <20060327125206.A2B6510079@code0.codespeak.net> Author: arigo Date: Mon Mar 27 14:52:05 2006 New Revision: 25032 Modified: pypy/dist/pypy/jit/hintcontainer.py pypy/dist/pypy/jit/hintmodel.py pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py Log: * VirtualRedBox.getgenvar() support. * fix the colors in pygame: use red for degenerated virtual structs too. Modified: pypy/dist/pypy/jit/hintcontainer.py ============================================================================== --- pypy/dist/pypy/jit/hintcontainer.py (original) +++ pypy/dist/pypy/jit/hintcontainer.py Mon Mar 27 14:52:05 2006 @@ -28,7 +28,11 @@ items = AbstractContainerDef.__cache[self.__class__, self.T].items() keys = [key for key, containerdef in items if containerdef.same_as(self)] tag = min(keys) - return "<%s #%d>" % (self.__class__.__name__, tag) + if self.degenerated: + degen = 'degen ' + else: + degen = '' + return "<%s%s #%d>" % (degen, self.__class__.__name__, tag) # ____________________________________________________________ Modified: pypy/dist/pypy/jit/hintmodel.py ============================================================================== --- pypy/dist/pypy/jit/hintmodel.py (original) +++ pypy/dist/pypy/jit/hintmodel.py Mon Mar 27 14:52:05 2006 @@ -101,12 +101,21 @@ pass class SomeLLAbstractContainer(SomeLLAbstractValue): - annotationcolor = (0,60,160) # blue def __init__(self, contentdef): self.contentdef = contentdef self.concretetype = lltype.Ptr(contentdef.T) + def annotationcolor(self): + """Compute the color of the variables with this annotation + for the pygame viewer + """ + if getattr(self.contentdef, 'degenerated', False): + return None + else: + return (0,60,160) # blue + annotationcolor = property(annotationcolor) + setunion = annmodel.setunion Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Mon Mar 27 14:52:05 2006 @@ -55,6 +55,7 @@ try: return self.red_reprs[lowleveltype] except KeyError: + assert not isinstance(lowleveltype, lltype.ContainerType) redreprcls = RedRepr if isinstance(lowleveltype, lltype.Ptr): if isinstance(lowleveltype.TO, lltype.Struct): @@ -123,15 +124,13 @@ fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_fieldname = rgenop.constFieldName(c_fieldname.value) gv_resulttype = rgenop.constTYPE(RESTYPE) - c_fieldname = hop.inputconst(rgenop.CONSTORVAR, gv_fieldname) c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getfield, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR, s_CONSTORVAR], - [v_jitstate, c_fielddesc, v_argbox, c_fieldname, c_resulttype], + [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR], + [v_jitstate, c_fielddesc, v_argbox, c_resulttype], ts.s_RedBox) def translate_op_getarrayitem(self, hop): @@ -171,13 +170,11 @@ fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_fieldname = rgenop.constFieldName(c_fieldname.value) - c_fieldname = hop.inputconst(rgenop.CONSTORVAR, gv_fieldname) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_setfield, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR, ts.s_RedBox], - [v_jitstate, c_fielddesc, v_destbox, c_fieldname, v_valuebox], + [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox], + [v_jitstate, c_fielddesc, v_destbox, v_valuebox], annmodel.s_None) def translate_op_getsubstruct(self, hop): @@ -192,15 +189,13 @@ fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_fieldname = rgenop.constFieldName(c_fieldname.value) gv_resulttype = rgenop.constTYPE(RESTYPE) - c_fieldname = hop.inputconst(rgenop.CONSTORVAR, gv_fieldname) c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getsubstruct, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR, s_CONSTORVAR], - [v_jitstate, c_fielddesc, v_argbox, c_fieldname, c_resulttype], + [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR], + [v_jitstate, c_fielddesc, v_argbox, c_resulttype], ts.s_RedBox) @@ -314,10 +309,12 @@ self.timeshifter = timeshifter def get_genop_var(self, v, llops): + ts = self.timeshifter + v_jitstate = hop.llops.getjitstate() return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_redbox, - [llops.timeshifter.s_RedBox], - [v], - annmodel.SomePtr(rgenop.CONSTORVAR)) + [ts.s_JITState, llops.timeshifter.s_RedBox], + [v_jitstate, v], + annmodel.SomePtr(rgenop.CONSTORVAR)) def convert_const(self, ll_value): redbox = rtimeshift.ConstRedBox.ll_fromvalue(ll_value) Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Mon Mar 27 14:52:05 2006 @@ -33,19 +33,19 @@ return False # generic implementation of some operations - def op_getfield(self, jitstate, fielddesc, gv_fieldname, gv_resulttype): + def op_getfield(self, jitstate, fielddesc, gv_resulttype): op_args = lltype.malloc(VARLIST.TO, 2) - op_args[0] = self.getgenvar() - op_args[1] = gv_fieldname + op_args[0] = self.getgenvar(jitstate) + op_args[1] = fielddesc.gv_fieldname genvar = rgenop.genop(jitstate.curblock, 'getfield', op_args, gv_resulttype) return VarRedBox(genvar) - def op_setfield(self, jitstate, fielddesc, gv_fieldname, valuebox): + def op_setfield(self, jitstate, fielddesc, valuebox): op_args = lltype.malloc(VARLIST.TO, 3) - op_args[0] = self.getgenvar() - op_args[1] = gv_fieldname - op_args[2] = valuebox.getgenvar() + op_args[0] = self.getgenvar(jitstate) + op_args[1] = fielddesc.gv_fieldname + op_args[2] = valuebox.getgenvar(jitstate) rgenop.genop(jitstate.curblock, 'setfield', op_args, gv_Void) @@ -56,7 +56,7 @@ def __init__(self, genvar): self.genvar = genvar - def getgenvar(self): + def getgenvar(self, jitstate): return self.genvar VCONTAINER = lltype.GcStruct("vcontainer") @@ -66,7 +66,7 @@ self.envelope = envelope self.content_addr = content_addr - def getgenvar(self): # not support at the moment + def getgenvar(self, jitstate): # no support at the moment raise RuntimeError("cannot force virtual containers") def ll_make_container_box(envelope, content_addr): @@ -90,17 +90,37 @@ class VirtualRedBox(RedBox): "A red box that contains (for now) a virtual Struct." - def __init__(self, content_boxes): - self.content_boxes = content_boxes[:] - - def getgenvar(self): # no support at the moment - raise RuntimeError("cannot force virtual containers") + def __init__(self, typedesc): + # XXX pass a TypeDesc instead of these arguments + self.content_boxes = typedesc.content_boxes[:] + self.typedesc = typedesc + self.genvar = rgenop.nullvar + + def getgenvar(self, jitstate): + if not self.genvar: + typedesc = self.typedesc + boxes = self.content_boxes + self.content_boxes = None + op_args = lltype.malloc(VARLIST.TO, 1) + op_args[0] = typedesc.gv_type + self.genvar = rgenop.genop(jitstate.curblock, 'malloc', op_args, + typedesc.gv_ptrtype) + for i in range(len(boxes)): + RedBox.op_setfield(self, jitstate, typedesc.fielddescs[i], + boxes[i]) + return self.genvar - def op_getfield(self, jitstate, fielddesc, gv_fieldname, gv_returntype): - return self.content_boxes[fielddesc.fieldindex] + def op_getfield(self, jitstate, fielddesc, gv_returntype): + if self.content_boxes is None: + return RedBox.op_getfield(self, jitstate, fielddesc, gv_returntype) + else: + return self.content_boxes[fielddesc.fieldindex] - def op_setfield(self, jitstate, fielddesc, gv_fieldname, valuebox): - self.content_boxes[fielddesc.fieldindex] = valuebox + def op_setfield(self, jitstate, fielddesc, valuebox): + if self.content_boxes is None: + RedBox.op_setfield(self, jitstate, fielddesc, valuebox) + else: + self.content_boxes[fielddesc.fieldindex] = valuebox def make_virtualredbox_factory_for_struct(T): defls = [] @@ -109,8 +129,10 @@ defaultvalue = FIELDTYPE._defl() defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) defls.append(defaultbox) + desc = ContainerTypeDesc(T) + desc.content_boxes = defls def ll_factory(): - return VirtualRedBox(defls) + return VirtualRedBox(desc) return ll_factory class ConstRedBox(RedBox): @@ -119,7 +141,7 @@ def __init__(self, genvar): self.genvar = genvar - def getgenvar(self): + def getgenvar(self, jitstate): return self.genvar def ll_fromvalue(value): @@ -130,6 +152,7 @@ elif T is lltype.Float: return DoubleRedBox(gv) else: + assert isinstance(T, lltype.Primitive) assert T is not lltype.Void, "cannot make red boxes of voids" # XXX what about long longs? return IntRedBox(gv) @@ -222,7 +245,7 @@ res = opdesc.llop(RESULT, arg) return ConstRedBox.ll_fromvalue(res) op_args = lltype.malloc(VARLIST.TO, 1) - op_args[0] = argbox.getgenvar() + op_args[0] = argbox.getgenvar(jitstate) genvar = rgenop.genop(jitstate.curblock, opdesc.opname, op_args, rgenop.constTYPE(RESULT)) return VarRedBox(genvar) @@ -240,17 +263,34 @@ res = opdesc.llop(RESULT, arg0, arg1) return ConstRedBox.ll_fromvalue(res) op_args = lltype.malloc(VARLIST.TO, 2) - op_args[0] = argbox0.getgenvar() - op_args[1] = argbox1.getgenvar() + op_args[0] = argbox0.getgenvar(jitstate) + op_args[1] = argbox1.getgenvar(jitstate) genvar = rgenop.genop(jitstate.curblock, opdesc.opname, op_args, rgenop.constTYPE(RESULT)) return VarRedBox(genvar) +class ContainerTypeDesc(object): + def __init__(self, TYPE): + self.TYPE = TYPE + self.PTRTYPE = lltype.Ptr(TYPE) + self.gv_type = rgenop.constTYPE(self.TYPE) + self.gv_ptrtype = rgenop.constTYPE(self.PTRTYPE) + # XXX only for Struct so far + self.fielddescs = [make_fielddesc(self.PTRTYPE, name) + for name in TYPE._names] + + def _freeze_(self): + return True + + def compact_repr(self): # goes in ll helper names + return "Desc_%s" % (self.TYPE._short_name(),) + class FieldDesc(object): # xxx should we use offsets instead def __init__(self, PTRTYPE, fieldname): self.PTRTYPE = PTRTYPE self.immutable = PTRTYPE.TO._hints.get('immutable', False) self.fieldname = fieldname + self.gv_fieldname = rgenop.constFieldName(fieldname) if isinstance(PTRTYPE.TO, lltype.Struct): try: self.fieldindex = operator.indexOf(PTRTYPE.TO._names, fieldname) @@ -273,28 +313,25 @@ fdesc = _fielddesc_cache[PTRTYPE, fieldname] = FieldDesc(PTRTYPE, fieldname) return fdesc -def ll_generate_getfield(jitstate, fielddesc, argbox, - gv_fieldname, gv_resulttype): +def ll_generate_getfield(jitstate, fielddesc, argbox, gv_resulttype): if fielddesc.immutable and isinstance(argbox, ConstRedBox): res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) return ConstRedBox.ll_fromvalue(res) - return argbox.op_getfield(jitstate, fielddesc, gv_fieldname, gv_resulttype) + return argbox.op_getfield(jitstate, fielddesc, gv_resulttype) gv_Void = rgenop.constTYPE(lltype.Void) -def ll_generate_setfield(jitstate, fielddesc, destbox, - gv_fieldname, valuebox): - destbox.op_setfield(jitstate, fielddesc, gv_fieldname, valuebox) +def ll_generate_setfield(jitstate, fielddesc, destbox, valuebox): + destbox.op_setfield(jitstate, fielddesc, valuebox) -def ll_generate_getsubstruct(jitstate, fielddesc, argbox, - gv_fieldname, gv_resulttype): +def ll_generate_getsubstruct(jitstate, fielddesc, argbox, gv_resulttype): if isinstance(argbox, ConstRedBox): res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) return ConstRedBox.ll_fromvalue(res) op_args = lltype.malloc(VARLIST.TO, 2) - op_args[0] = argbox.getgenvar() - op_args[1] = gv_fieldname + op_args[0] = argbox.getgenvar(jitstate) + op_args[1] = fielddesc.gv_fieldname genvar = rgenop.genop(jitstate.curblock, 'getsubstruct', op_args, gv_resulttype) return VarRedBox(genvar) @@ -307,8 +344,8 @@ res = argbox.ll_getvalue(fielddesc.PTRTYPE)[indexbox.ll_getvalue(lltype.Signed)] return ConstRedBox.ll_fromvalue(res) op_args = lltype.malloc(VARLIST.TO, 2) - op_args[0] = argbox.getgenvar() - op_args[1] = indexbox.getgenvar() + op_args[0] = argbox.getgenvar(jitstate) + op_args[1] = indexbox.getgenvar(jitstate) genvar = rgenop.genop(jitstate.curblock, 'getarrayitem', op_args, gv_resulttype) return VarRedBox(genvar) @@ -336,7 +373,7 @@ oldbox = oldboxes[i] newbox = redboxes[i] if isinstance(oldbox, VarRedBox): # Always a match - incoming.append(newbox.getgenvar()) + incoming.append(newbox.getgenvar(jitstate)) continue if oldbox.same_constant(newbox): continue @@ -353,7 +390,7 @@ oldbox = oldboxes[i] newbox = redboxes[i] if not oldbox.same_constant(newbox): - incoming.append(newbox.getgenvar()) + incoming.append(newbox.getgenvar(jitstate)) newgenvar = rgenop.geninputarg(newblock, TYPES[i]) redboxes[i] = VarRedBox(newgenvar) @@ -387,7 +424,7 @@ jitstate.curoutgoinglink = rgenop.closeblock1(jitstate.curblock) return switchredbox.ll_getvalue(lltype.Bool) else: - exitgvar = switchredbox.getgenvar() + exitgvar = switchredbox.getgenvar(jitstate) linkpair = rgenop.closeblock2(jitstate.curblock, exitgvar) false_link, true_link = linkpair.item0, linkpair.item1 later_jitstate = jitstate.copystate() @@ -429,15 +466,15 @@ finalvar = rgenop.geninputarg(finalblock, RETURN_TYPE) for link, redbox in return_queue: - genvar = redbox.getgenvar() + genvar = redbox.getgenvar(jitstate) rgenop.closelink(link, [genvar], finalblock) finallink = rgenop.closeblock1(finalblock) jitstate.curoutgoinglink = finallink jitstate.curvalue = VarRedBox(finalvar) return -1 -def ll_gvar_from_redbox(redbox): - return redbox.getgenvar() +def ll_gvar_from_redbox(jitstate, redbox): + return redbox.getgenvar(jitstate) def ll_gvar_from_constant(ll_value): return rgenop.genconst(ll_value) @@ -491,5 +528,5 @@ return jitstate.curblock def ll_close_jitstate(jitstate): - result_genvar = jitstate.curvalue.getgenvar() + result_genvar = jitstate.curvalue.getgenvar(jitstate) jitstate.close(result_genvar) From ac at codespeak.net Mon Mar 27 15:44:15 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Mar 2006 15:44:15 +0200 (CEST) Subject: [pypy-svn] r25033 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060327134415.46A251009A@code0.codespeak.net> Author: ac Date: Mon Mar 27 15:44:09 2006 New Revision: 25033 Modified: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt (contents, props changed) Log: Fix ReST-problem and eol-style Modified: pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/sprint-announcement.txt Mon Mar 27 15:44:09 2006 @@ -1,150 +1,150 @@ -Tokyo PyPy Sprint: 23rd - 29th April 2006 -============================================================ - -The next PyPy sprint is scheduled to take place 23rd- 29th April 2006 -(Sunday-Saturday) in Akihabara, Tokyo, Japan. We will together with -FSIJ (Free Software Initiative of Japan) aim to promote Python and -PyPy. We therefor invite Japanese hackers knowledgeable in Python to -join our sprint! We'll give newcomer-friendly introductions. To learn -more about the new Python-in-Python implementation look here: - - http://codespeak.net/pypy - -For this sprint we are particularly interested in meeting and coding on PyPy together -with interested Japanese Python hackers. Please register your interest at pypy-sprint at codespeak.net -as soon as possible and we will help with any questions regarding getting started, pointing -to relevant documentation etc. - -The PyPy team is curious and interested in the experience of hacking code for embedded devices -and would love to discuss and get feedback on optimisation efforts and the current state of PyPy. - -Goals and topics of the sprint ------------------------------- - -Possible suggestions for topics are: - - - Work on gensqueak (our Squeak backend) or possibly other backends. - - - Implementing Python 2.5 features in PyPy. - - - Progress further on an 'rctypes' module aiming at letting us use a ctypes - implementation of an extension module from the compiled pypy-c. - - - Writing ctypes implementations of modules to be used by the above - tool. - - - Experimenting and improving performance of our garbage collectors. - - - Experiment with PyPy flexibility or other aspects of the implementation. - - - Possibly experiment with writing modules translatable for use both - in PyPy and CPython. - - - Whatever participants want to do with PyPy or particular areas - of PyPy (please send suggestions to the mailing list before to allow us to plan - and give feedback) - - -Location & Accomodation ------------------------- - -The sprint will be held at National Institute of AIST - (National Institute of Advanced Industrial Science and Technology, - http://www.aist.go.jp/index_en.html), Akihahabara (the technical gadget -district in Tokyo). Yutaka Niibe is our contact person there, -helping with arranging facilities. Niibe is the chairman of FSIJ and they have -invited us to sprint in Tokyo and we are very grateful for the help and interest -we have recieved so far. - -The facilities we are sprinting in are located here: - - http://www.gtrc.aist.go.jp/en/access/index.html#Akihabara - - -The actual address is: -Akihabara Dai Bldg , 1-18-13 Sotokanda, Chiyoda-ku, Tokyo 101-0021 Japan -Phone: +81-3-5298-4729 - -Hotel areas - we are recommended to book hotels in Ueno and Asakusa (old town), -from those areas there are only two metro stops to Akihabara. Please note that -hotelrooms in Tokyo are often very small. - - http://www.wh-rsv.com/english/akihabara/index.html (nearest hotel to sprint location) - http://www.greenhotel.co.jp/ochanomizu_e.html - http://www.ohgai.co.jp/index-e.html (Ueno) - http://www.toyoko-inn.com/e_hotel/00012/index.html (Asakusa) - http://www.hotelnewkanda.com/ (second nearest, but no english page) - -Here is a url for booking hotels with not too unreasonable rates (see map): -http://japan-hotelguide.com/hotels/Japan/Tokyo/index.htm - -For more general tourist information about travelling to Japan and Tokyo - please see: -http://www.jnto.go.jp/eng/ -http://www.japantravelinfo.com/ (really useful information regarding airfares, hotels, currency, phones etc etc) - -Comments on the weather: In end April it is ca 20 degrees Celsius. - - -Exact times ------------ - -The public PyPy sprint is held Sunday 23rd - Saturday 29th April 2006. -Hours will be from 10:00 until people have had enough. It's a good idea -to arrive a day before the sprint starts and leave a day later. Sometimes people -cannot stay for the whole sprint - you are welcome even if you can only stay -for a day or a few days. - -Sunday: Starting at 10:00. This day is focused on getting to know PyPy enought to -start to participate. We will hold a PyPy tutorial and an architectural overview. -Planning meeting for the work to be done during the week and grouping of developers (pairs -or groups mixing new participants with core developers). - -Dinner in the evening (Yutaka will arrange a place for us to go to). - -Monday-Tuesday: Starting at 10:00 with status meetings. Possible regrouping -depending on the interest and progress of the various teams. - -Wednesday: Breakday (coding is allowed although we recommend taking a break). - -Thursday-Saturday: Starting at 10:00 with status meetings. Possible regrouping -depending on the interest and progress of the various teams. Ending on Saturday with -a Closure session - summing of the work and planning work to be done until the next sprint. - - -Network, Food, currency ------------------------- - -We will have access to WiFi at AIST - please make sure you have wlan capabilities. - -Electricity outlets: 100V (adapters needed for european standard). - -Currency is Japanese yen. There are Citibank cash machines that -accepts cash withdrawals from the major cards such as VISA and Mastercard. -But it is a good idea to bring cash. - -Also note that cell phones (european) are not very compatible with the Japanese -network. There are possibilities for 3G phones to hire a phone and put your simcard -in there. At the airport (both Kansai and Narita) there are information and places -were this can be arranged (to a cost of course). - -Food: well - japanese food is great (wether it is sushi, sashimi, tempura, sukiyaki, teriyaki.... -Eating out is not that much differently prized -than any large european town. There are of course restaurants serving -other food than japanese (chinese, korean, McDonalds ;-). -Please also note that vegetables and fruit is quite expensive in Japan. - -For more information - see tourist url:s above. - -Registration etc.pp. --------------------- - -Please subscribe to the `PyPy sprint mailing list`_, introduce yourself -and post a note that you want to come. Feel free to ask any questions -there! There also is a separate `Tokyo people`_ page tracking who is -already thought to come. If you have commit rights on codespeak then -you can modify yourself a checkout of - - http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt - -.. _`PyPy sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint -.. _`Tokyo people`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/people.html +Tokyo PyPy Sprint: 23rd - 29th April 2006 +============================================================ + +The next PyPy sprint is scheduled to take place 23rd- 29th April 2006 +(Sunday-Saturday) in Akihabara, Tokyo, Japan. We will together with +FSIJ (Free Software Initiative of Japan) aim to promote Python and +PyPy. We therefor invite Japanese hackers knowledgeable in Python to +join our sprint! We'll give newcomer-friendly introductions. To learn +more about the new Python-in-Python implementation look here: + + http://codespeak.net/pypy + +For this sprint we are particularly interested in meeting and coding on PyPy together +with interested Japanese Python hackers. Please register your interest at pypy-sprint at codespeak.net +as soon as possible and we will help with any questions regarding getting started, pointing +to relevant documentation etc. + +The PyPy team is curious and interested in the experience of hacking code for embedded devices +and would love to discuss and get feedback on optimisation efforts and the current state of PyPy. + +Goals and topics of the sprint +------------------------------ + +Possible suggestions for topics are: + + - Work on gensqueak (our Squeak backend) or possibly other backends. + + - Implementing Python 2.5 features in PyPy. + + - Progress further on an 'rctypes' module aiming at letting us use a ctypes + implementation of an extension module from the compiled pypy-c. + + - Writing ctypes implementations of modules to be used by the above + tool. + + - Experimenting and improving performance of our garbage collectors. + + - Experiment with PyPy flexibility or other aspects of the implementation. + + - Possibly experiment with writing modules translatable for use both + in PyPy and CPython. + + - Whatever participants want to do with PyPy or particular areas + of PyPy (please send suggestions to the mailing list before to allow us to plan + and give feedback) + + +Location & Accomodation +------------------------ + +The sprint will be held at National Institute of AIST +(National Institute of Advanced Industrial Science and Technology, +http://www.aist.go.jp/index_en.html), Akihahabara (the technical gadget +district in Tokyo). Yutaka Niibe is our contact person there, +helping with arranging facilities. Niibe is the chairman of FSIJ and they have +invited us to sprint in Tokyo and we are very grateful for the help and interest +we have recieved so far. + +The facilities we are sprinting in are located here: + + http://www.gtrc.aist.go.jp/en/access/index.html#Akihabara + + +The actual address is: +Akihabara Dai Bldg , 1-18-13 Sotokanda, Chiyoda-ku, Tokyo 101-0021 Japan +Phone: +81-3-5298-4729 + +Hotel areas - we are recommended to book hotels in Ueno and Asakusa (old town), +from those areas there are only two metro stops to Akihabara. Please note that +hotelrooms in Tokyo are often very small. + + http://www.wh-rsv.com/english/akihabara/index.html (nearest hotel to sprint location) + http://www.greenhotel.co.jp/ochanomizu_e.html + http://www.ohgai.co.jp/index-e.html (Ueno) + http://www.toyoko-inn.com/e_hotel/00012/index.html (Asakusa) + http://www.hotelnewkanda.com/ (second nearest, but no english page) + +Here is a url for booking hotels with not too unreasonable rates (see map): +http://japan-hotelguide.com/hotels/Japan/Tokyo/index.htm + +For more general tourist information about travelling to Japan and Tokyo - please see: +http://www.jnto.go.jp/eng/ +http://www.japantravelinfo.com/ (really useful information regarding airfares, hotels, currency, phones etc etc) + +Comments on the weather: In end April it is ca 20 degrees Celsius. + + +Exact times +----------- + +The public PyPy sprint is held Sunday 23rd - Saturday 29th April 2006. +Hours will be from 10:00 until people have had enough. It's a good idea +to arrive a day before the sprint starts and leave a day later. Sometimes people +cannot stay for the whole sprint - you are welcome even if you can only stay +for a day or a few days. + +Sunday: Starting at 10:00. This day is focused on getting to know PyPy enought to +start to participate. We will hold a PyPy tutorial and an architectural overview. +Planning meeting for the work to be done during the week and grouping of developers (pairs +or groups mixing new participants with core developers). + +Dinner in the evening (Yutaka will arrange a place for us to go to). + +Monday-Tuesday: Starting at 10:00 with status meetings. Possible regrouping +depending on the interest and progress of the various teams. + +Wednesday: Breakday (coding is allowed although we recommend taking a break). + +Thursday-Saturday: Starting at 10:00 with status meetings. Possible regrouping +depending on the interest and progress of the various teams. Ending on Saturday with +a Closure session - summing of the work and planning work to be done until the next sprint. + + +Network, Food, currency +------------------------ + +We will have access to WiFi at AIST - please make sure you have wlan capabilities. + +Electricity outlets: 100V (adapters needed for european standard). + +Currency is Japanese yen. There are Citibank cash machines that +accepts cash withdrawals from the major cards such as VISA and Mastercard. +But it is a good idea to bring cash. + +Also note that cell phones (european) are not very compatible with the Japanese +network. There are possibilities for 3G phones to hire a phone and put your simcard +in there. At the airport (both Kansai and Narita) there are information and places +were this can be arranged (to a cost of course). + +Food: well - japanese food is great (wether it is sushi, sashimi, tempura, sukiyaki, teriyaki.... +Eating out is not that much differently prized +than any large european town. There are of course restaurants serving +other food than japanese (chinese, korean, McDonalds ;-). +Please also note that vegetables and fruit is quite expensive in Japan. + +For more information - see tourist url:s above. + +Registration etc.pp. +-------------------- + +Please subscribe to the `PyPy sprint mailing list`_, introduce yourself +and post a note that you want to come. Feel free to ask any questions +there! There also is a separate `Tokyo people`_ page tracking who is +already thought to come. If you have commit rights on codespeak then +you can modify yourself a checkout of + + http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt + +.. _`PyPy sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint +.. _`Tokyo people`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/people.html From ac at codespeak.net Mon Mar 27 15:45:00 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Mar 2006 15:45:00 +0200 (CEST) Subject: [pypy-svn] r25034 - pypy/dist/pypy/doc Message-ID: <20060327134500.3886D10088@code0.codespeak.net> Author: ac Date: Mon Mar 27 15:44:59 2006 New Revision: 25034 Modified: pypy/dist/pypy/doc/events.txt pypy/dist/pypy/doc/news.txt Log: Add Tokyo sprint information. Modified: pypy/dist/pypy/doc/events.txt ============================================================================== --- pypy/dist/pypy/doc/events.txt (original) +++ pypy/dist/pypy/doc/events.txt Mon Mar 27 15:44:59 2006 @@ -19,3 +19,19 @@ *April 23rd - April 29th 2006.* +The sprint will be Akihabara, Tokyo, Japan. Our hosts are +FSIJ (Free Software Initiative of Japan) and out aim for the sprint +will be to promote Python and introduce people to PyPy. + +Read more in `the announcement`_, see who is planning to attend +on the `people page`_. + +.. _`the announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-announcement.html +.. _`People page`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt + +Sprint in Tokyo (Japan) +=================================================================== + +*April 23rd - April 29th 2006.* + + Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Mon Mar 27 15:44:59 2006 @@ -7,6 +7,18 @@ .. _Python: http://www.python.org/doc/current/ref/ref.html .. _`more...`: http://codespeak.net/pypy/dist/pypy/doc/architecture.html#mission-statement +Next PyPy sprint in Tokyo 23rd - 29th April 2006 +================================================================== + +The next sprint will be Akihabara, Tokyo, Japan. Our hosts are +FSIJ (Free Software Initiative of Japan) and out aim for the sprint +will be to promote Python and introduce people to PyPy. + +Read more in `the sprint announcement`_, see who is planning to attend +on the `people page`_. + +.. _`the sprint announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-announcement.html +.. _`people page`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.html Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) ======================================================================== From ac at codespeak.net Mon Mar 27 15:51:22 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Mar 2006 15:51:22 +0200 (CEST) Subject: [pypy-svn] r25035 - pypy/dist/pypy/doc Message-ID: <20060327135122.B52901008A@code0.codespeak.net> Author: ac Date: Mon Mar 27 15:51:22 2006 New Revision: 25035 Modified: pypy/dist/pypy/doc/news.txt Log: Fix bad URL. Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Mon Mar 27 15:51:22 2006 @@ -18,7 +18,7 @@ on the `people page`_. .. _`the sprint announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-announcement.html -.. _`people page`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.html +.. _`people page`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/people.html Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) ======================================================================== From ac at codespeak.net Mon Mar 27 16:11:38 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Mar 2006 16:11:38 +0200 (CEST) Subject: [pypy-svn] r25037 - pypy/extradoc/planning/malaga_exhibition_feb2006 Message-ID: <20060327141138.A77AA10088@code0.codespeak.net> Author: ac Date: Mon Mar 27 16:11:37 2006 New Revision: 25037 Modified: pypy/extradoc/planning/malaga_exhibition_feb2006/information_pypy_malaga.txt Log: Fix ReST-problem. Modified: pypy/extradoc/planning/malaga_exhibition_feb2006/information_pypy_malaga.txt ============================================================================== --- pypy/extradoc/planning/malaga_exhibition_feb2006/information_pypy_malaga.txt (original) +++ pypy/extradoc/planning/malaga_exhibition_feb2006/information_pypy_malaga.txt Mon Mar 27 16:11:37 2006 @@ -86,7 +86,7 @@ Conference Chairman II Open Source World Conference MALAGA 15-17 FEBRUARY 2006 - +34670644131-FAX +34670641066 ++34670644131-FAX +34670641066 chairman at opensourceworldconference.com www.opensourceworldconference.com @@ -148,4 +148,4 @@ +34670644131 chairman at opensourceworldconference.com -www.opensourceworldconference.com \ No newline at end of file +www.opensourceworldconference.com From ac at codespeak.net Mon Mar 27 16:13:51 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Mar 2006 16:13:51 +0200 (CEST) Subject: [pypy-svn] r25038 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060327141351.E3F2F100A2@code0.codespeak.net> Author: ac Date: Mon Mar 27 16:13:51 2006 New Revision: 25038 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: Dates for me and Samuele. Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Mon Mar 27 16:13:51 2006 @@ -15,8 +15,8 @@ Laura Creighton Anders Lehmann 23/4 - 1/5 ? Niklaus Haldimann -Anders Chrigstr?m -Samuele Pedroni +Anders Chrigstr?m 22/4 - 30/4 +Samuele Pedroni 22/4 - 30/4 ==================== ============== ===================== People on the following list were present at previous sprints: From bea at codespeak.net Mon Mar 27 16:49:33 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Mon, 27 Mar 2006 16:49:33 +0200 (CEST) Subject: [pypy-svn] r25039 - pypy/extradoc/pypy.org Message-ID: <20060327144933.6348810077@code0.codespeak.net> Author: bea Date: Mon Mar 27 16:49:31 2006 New Revision: 25039 Modified: pypy/extradoc/pypy.org/news.txt Log: info about the tokyo sprint Modified: pypy/extradoc/pypy.org/news.txt ============================================================================== --- pypy/extradoc/pypy.org/news.txt (original) +++ pypy/extradoc/pypy.org/news.txt Mon Mar 27 16:49:31 2006 @@ -1,4 +1,10 @@ - +PyPy sprint in Tokyo 23rd-29th of April, 2006 +----------------------------------------------- +The PyPy team has been invited by FSIJ (Free Software Initiative Japan) +to sprint in the facilities of the National Institute of Advanced Technology +and Science in Akihabara, Tokyo. The sprint is aiming at dissemination of +the current state of PyPy within the community of Japanese Hackers. +See more on http://codespeak.net/pypy/dist/pypy/doc/news.html. PyPy sprint in Louvain-La-Neuve 6-10th of March, 2006 From cfbolz at codespeak.net Mon Mar 27 17:03:42 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Mar 2006 17:03:42 +0200 (CEST) Subject: [pypy-svn] r25041 - pypy/dist/pypy/translator/backendopt Message-ID: <20060327150342.8E05E10078@code0.codespeak.net> Author: cfbolz Date: Mon Mar 27 17:03:40 2006 New Revision: 25041 Modified: pypy/dist/pypy/translator/backendopt/all.py pypy/dist/pypy/translator/backendopt/stat.py Log: (cfbolz, pedronis): add statistics per graph (sorted by hash of bytecode to make it more diffable) Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Mon Mar 27 17:03:40 2006 @@ -22,7 +22,7 @@ if PRINT_STATISTICS: print "before optimizations:" - print_statistics(translator.graphs[0], translator) + print_statistics(translator.graphs[0], translator, "per-graph.txt") if raisingop2direct_call_all: raisingop2direct_call(translator) Modified: pypy/dist/pypy/translator/backendopt/stat.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/stat.py (original) +++ pypy/dist/pypy/translator/backendopt/stat.py Mon Mar 27 17:03:40 2006 @@ -1,17 +1,21 @@ from pypy.translator.simplify import get_graph +import md5 -def get_statistics(graph, translator): +def get_statistics(graph, translator, save_per_graph_details=None): seen_graphs = {} stack = [graph] num_graphs = 0 num_blocks = 0 num_ops = 0 + per_graph = {} while stack: graph = stack.pop() if graph in seen_graphs: continue seen_graphs[graph] = True num_graphs += 1 + old_num_blocks = num_blocks + old_num_ops = num_ops for block in graph.iterblocks(): num_blocks += 1 for op in block.operations: @@ -24,10 +28,27 @@ if called_graphs is not None: stack.extend(called_graphs) num_ops += 1 + per_graph[graph] = (num_blocks-old_num_blocks, num_ops-old_num_ops) + if save_per_graph_details: + details = [] + for graph, (nblocks, nops) in per_graph.iteritems(): + try: + code = graph.func.func_code.co_code + except AttributeError: + code = "None" + hash = md5.new(code).hexdigest() + details.append((hash, graph.name, nblocks, nops)) + details.sort() + f = open(save_per_graph_details, "w") + try: + for hash, name, nblocks, nops in details: + print >>f, hash, name, nblocks, nops + finally: + f.close() return num_graphs, num_blocks, num_ops -def print_statistics(graph, translator): - num_graphs, num_blocks, num_ops = get_statistics(graph, translator) +def print_statistics(graph, translator, save_per_graph_details=None): + num_graphs, num_blocks, num_ops = get_statistics(graph, translator, save_per_graph_details) print ("Statistics:\nnumber of graphs %s\n" "number of blocks %s\n" "number of operations %s\n") % (num_graphs, num_blocks, num_ops) From antocuni at codespeak.net Mon Mar 27 17:29:17 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 27 Mar 2006 17:29:17 +0200 (CEST) Subject: [pypy-svn] r25042 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060327152917.DC62210088@code0.codespeak.net> Author: antocuni Date: Mon Mar 27 17:28:57 2006 New Revision: 25042 Modified: pypy/dist/pypy/translator/cli/conftest.py pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/gencli.py pypy/dist/pypy/translator/cli/test/compile.py pypy/dist/pypy/translator/cli/test/runtest.py Log: Fixed conftest-related bug (I hope!) Modified: pypy/dist/pypy/translator/cli/conftest.py ============================================================================== --- pypy/dist/pypy/translator/cli/conftest.py (original) +++ pypy/dist/pypy/translator/cli/conftest.py Mon Mar 27 17:28:57 2006 @@ -17,3 +17,4 @@ Option('--nostop', action="store_true", dest="nostop", default=False, help="don't stop on warning. The generated IL code could not compile") ) + Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Mon Mar 27 17:28:57 2006 @@ -4,7 +4,7 @@ from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong -from pypy.translator.cli import conftest +from pypy.translator.cli.options import getoption from pypy.tool.ansi_print import ansi_log import py @@ -35,7 +35,7 @@ try: return _lltype_to_cts[t] except KeyError: - if conftest.option.nostop: + if getoption('nostop'): log.WARNING('Unknown type %s' % t) return t else: @@ -48,7 +48,7 @@ try: return _cts_to_ilasm[t] except KeyError: - if conftest.option.nostop: + if getoption('nostop'): log.WARNING('Unknown ilasm type %s' % t) return t else: Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Mon Mar 27 17:28:57 2006 @@ -1,6 +1,6 @@ from pypy.objspace.flow import model as flowmodel from pypy.rpython.lltypesystem.lltype import Void -from pypy.translator.cli import conftest +from pypy.translator.cli.options import getoption from pypy.translator.cli import cts from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs @@ -140,7 +140,7 @@ elif opname == 'direct_call': self._call(op) else: - if conftest.option.nostop: + if getoption('nostop'): log.WARNING('Unknown opcode: %s ' % op) self.ilasm.opcode(str(op)) else: Modified: pypy/dist/pypy/translator/cli/gencli.py ============================================================================== --- pypy/dist/pypy/translator/cli/gencli.py (original) +++ pypy/dist/pypy/translator/cli/gencli.py Mon Mar 27 17:28:57 2006 @@ -3,6 +3,8 @@ from pypy.translator.cli import conftest from pypy.translator.cli.ilgenerator import IlasmGenerator from pypy.translator.cli.function import Function +from pypy.translator.cli.options import getoption + class Tee(object): def __init__(self, *args): @@ -32,7 +34,7 @@ def generate_source(self): out = self.tmpfile.open('w') - if conftest.option.stdout: + if getoption('stdout'): out = Tee(sys.stdout, out) self.ilasm = IlasmGenerator(out, self.assembly_name) Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Mon Mar 27 17:28:57 2006 @@ -2,7 +2,7 @@ import sys import py -from pypy.rpython.rarithmetic import r_int, r_uint, r_ulonglong, r_longlong +from pypy.rpython.rarithmetic import r_int, r_uint, r_ulonglong, r_longlong, ovfcheck from pypy.translator.test import snippet as s from pypy.translator.cli import conftest from pypy.translator.cli.test.runtest import compile_function @@ -24,11 +24,31 @@ print 'OK' +def foo(x): + pass + +def xxx(): + pass + +def bar(x, y): + try: + foo(x) + z = ovfcheck(x+y) + xxx() + return z + except OverflowError: + while x: + x = x-1 + return x + except IndexError: + return 52 + def bar(x, y): - return x and (not y) + foo(x) + foo(None) -f = compile_function(bar, [r_uint, r_uint]) +f = compile_function(bar, [int, int]) try: check(f, bar, r_uint(sys.maxint+1), r_uint(42)) Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Mon Mar 27 17:28:57 2006 @@ -5,8 +5,7 @@ import py from pypy.tool.udir import udir from pypy.translator.translator import TranslationContext -from pypy.translator.cli import conftest -from pypy.conftest import option +from pypy.translator.cli.options import getoption from pypy.translator.cli.gencli import GenCli from pypy.translator.cli.function import Node from pypy.translator.cli.cts import graph_to_signature @@ -95,10 +94,10 @@ t.buildrtyper(type_system="ootype").specialize() self.graph = t.graphs[0] - if option.view: + if getoption('view'): t.viewcg() - if option.wd: + if getoption('wd'): tmpdir = py.path.local('.') else: tmpdir = udir @@ -120,7 +119,7 @@ def _build_exe(self): tmpfile = self._gen.generate_source() - if option.source: + if getoption('source'): return None self.__check_helper("ilasm") From arigo at codespeak.net Mon Mar 27 18:21:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 18:21:29 +0200 (CEST) Subject: [pypy-svn] r25045 - pypy/dist/pypy/jit Message-ID: <20060327162129.D7DC510083@code0.codespeak.net> Author: arigo Date: Mon Mar 27 18:21:28 2006 New Revision: 25045 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py Log: light refactorings, and support for directly calling methods of frozen PBCs as mix-level helpers. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Mon Mar 27 18:21:28 2006 @@ -1,3 +1,4 @@ +import types from pypy.annotation import model as annmodel from pypy.annotation.pairtype import pair, pairtype from pypy.rpython import annlowlevel @@ -218,11 +219,23 @@ def genmixlevelhelpercall(self, function, args_s, args_v, s_result): # XXX first approximation, will likely need some fine controlled # specialisation for these helpers too - rtyper = self.timeshifter.rtyper + + if isinstance(function, types.MethodType): + if function.im_self is not None: + # bound method => function and an extra first argument + bk = self.rtyper.annotator.bookkeeper + s_self = bk.immutablevalue(function.im_self) + r_self = self.rtyper.getrepr(s_self) + v_self = inputconst(r_self.lowleveltype, + r_self.convert_const(function.im_self)) + args_s = [s_self] + args_s + args_v = [v_self] + args_v + function = function.im_func graph = self.timeshifter.annhelper.getgraph(function, args_s, s_result) self.record_extra_call(graph) # xxx + rtyper = self.timeshifter.rtyper ARGS = [rtyper.getrepr(s_arg).lowleveltype for s_arg in args_s] RESULT = rtyper.getrepr(s_result).lowleveltype @@ -326,14 +339,14 @@ class RedStructRepr(RedRepr): - ll_factory = None + typedesc = None def create(self, hop): - if self.ll_factory is None: + if self.typedesc is None: T = self.original_concretetype.TO - self.ll_factory = rtimeshift.make_virtualredbox_factory_for_struct(T) + self.typedesc = rtimeshift.ContainerTypeDesc(T) ts = self.timeshifter - return hop.llops.genmixlevelhelpercall(self.ll_factory, + return hop.llops.genmixlevelhelpercall(self.typedesc.ll_factory, [], [], ts.s_RedBox) Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Mon Mar 27 18:21:28 2006 @@ -91,7 +91,6 @@ "A red box that contains (for now) a virtual Struct." def __init__(self, typedesc): - # XXX pass a TypeDesc instead of these arguments self.content_boxes = typedesc.content_boxes[:] self.typedesc = typedesc self.genvar = rgenop.nullvar @@ -122,19 +121,6 @@ else: self.content_boxes[fielddesc.fieldindex] = valuebox -def make_virtualredbox_factory_for_struct(T): - defls = [] - for name in T._names: - FIELDTYPE = T._flds[name] - defaultvalue = FIELDTYPE._defl() - defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) - defls.append(defaultbox) - desc = ContainerTypeDesc(T) - desc.content_boxes = defls - def ll_factory(): - return VirtualRedBox(desc) - return ll_factory - class ConstRedBox(RedBox): "A red box that contains a run-time constant." @@ -278,6 +264,16 @@ # XXX only for Struct so far self.fielddescs = [make_fielddesc(self.PTRTYPE, name) for name in TYPE._names] + defls = [] + for name in TYPE._names: + FIELDTYPE = TYPE._flds[name] + defaultvalue = FIELDTYPE._defl() + defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) + defls.append(defaultbox) + self.content_boxes = defls + + def ll_factory(self): + return VirtualRedBox(self) def _freeze_(self): return True From arigo at codespeak.net Mon Mar 27 19:44:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 19:44:55 +0200 (CEST) Subject: [pypy-svn] r25046 - pypy/dist/pypy/rpython Message-ID: <20060327174455.00F6510079@code0.codespeak.net> Author: arigo Date: Mon Mar 27 19:44:54 2006 New Revision: 25046 Modified: pypy/dist/pypy/rpython/rgenop.py Log: Forgot to check this in. Modified: pypy/dist/pypy/rpython/rgenop.py ============================================================================== --- pypy/dist/pypy/rpython/rgenop.py (original) +++ pypy/dist/pypy/rpython/rgenop.py Mon Mar 27 19:44:54 2006 @@ -223,6 +223,8 @@ fields = tuple(zip(fieldnames, lltypes)) LINKPAIR = lltype.GcStruct('tuple2', *fields) +nullvar = lltype.nullptr(CONSTORVAR.TO) + # helpers def setannotation(func, TYPE): func.compute_result_annotation = lambda *args_s: TYPE From arigo at codespeak.net Mon Mar 27 19:46:44 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 19:46:44 +0200 (CEST) Subject: [pypy-svn] r25047 - in pypy/dist/pypy/rpython: . test Message-ID: <20060327174644.0CDC61007B@code0.codespeak.net> Author: arigo Date: Mon Mar 27 19:46:32 2006 New Revision: 25047 Modified: pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: Yet another case for rpbc.py: converting from multiple to single frozen pbcs, a case I just hit in the jit. Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Mon Mar 27 19:46:32 2006 @@ -475,6 +475,11 @@ return inputdesc(r_pbc2, frozendesc1) return NotImplemented +class __extend__(pairtype(AbstractMultipleUnrelatedFrozenPBCRepr, + SingleFrozenPBCRepr)): + def convert_from_to((r_pbc1, r_pbc2), v, llops): + return inputconst(Void, r_pbc2.frozendesc) + class MethodOfFrozenPBCRepr(Repr): """Representation selected for a PBC of method object(s) of frozen PBCs. Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Mon Mar 27 19:46:32 2006 @@ -1150,6 +1150,21 @@ res = interpret(f, [3], type_system=self.ts) assert res == 42 + def test_convert_multiple_to_single(self): + class A: + def meth(self, fr): + return 65 + class B(A): + def meth(self, fr): + return 66 + fr1 = Freezing() + fr2 = Freezing() + def f(): + return A().meth(fr1) * B().meth(fr2) + + res = interpret(f, [], type_system=self.ts) + assert res == 65*66 + def test_call_from_list(): # Don't test with ootype, since it doesn't support lists in a From arigo at codespeak.net Mon Mar 27 19:49:09 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Mar 2006 19:49:09 +0200 (CEST) Subject: [pypy-svn] r25048 - pypy/dist/pypy/jit Message-ID: <20060327174909.C027810081@code0.codespeak.net> Author: arigo Date: Mon Mar 27 19:48:58 2006 New Revision: 25048 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py Log: Some more light refactoring. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Mon Mar 27 19:48:58 2006 @@ -119,19 +119,16 @@ return res ts = self.timeshifter - RESTYPE = originalconcretetype(hop.s_result) v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), green_void_repr) - fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) + fielddesc = rtimeshift.StructFieldDesc.make(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_resulttype = rgenop.constTYPE(RESTYPE) - c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getfield, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR], - [v_jitstate, c_fielddesc, v_argbox, c_resulttype], + [ts.s_JITState, s_fielddesc, ts.s_RedBox], + [v_jitstate, c_fielddesc, v_argbox ], ts.s_RedBox) def translate_op_getarrayitem(self, hop): @@ -142,19 +139,16 @@ return res ts = self.timeshifter - RESTYPE = originalconcretetype(hop.s_result) v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), self.getredrepr(lltype.Signed)) - fielddesc = rtimeshift.make_fielddesc(PTRTYPE, '-') + fielddesc = rtimeshift.ArrayFieldDesc.make(PTRTYPE) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_resulttype = rgenop.constTYPE(RESTYPE) - c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getarrayitem, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox, s_CONSTORVAR], - [v_jitstate, c_fielddesc, v_argbox, v_index, c_resulttype], + [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox], + [v_jitstate, c_fielddesc, v_argbox, v_index ], ts.s_RedBox) def translate_op_setfield(self, hop): @@ -168,7 +162,7 @@ green_void_repr, self.getredrepr(VALUETYPE) ) - fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) + fielddesc = rtimeshift.StructFieldDesc.make(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) v_jitstate = hop.llops.getjitstate() @@ -184,19 +178,16 @@ # non virtual case ts = self.timeshifter PTRTYPE = originalconcretetype(hop.args_s[0]) - RESTYPE = originalconcretetype(hop.s_result) v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), green_void_repr) - fielddesc = rtimeshift.make_fielddesc(PTRTYPE, c_fieldname.value) + fielddesc = rtimeshift.StructFieldDesc.make(PTRTYPE, c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) - gv_resulttype = rgenop.constTYPE(RESTYPE) - c_resulttype = hop.inputconst(rgenop.CONSTORVAR, gv_resulttype) v_jitstate = hop.llops.getjitstate() s_CONSTORVAR = annmodel.SomePtr(rgenop.CONSTORVAR) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_generate_getsubstruct, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, s_CONSTORVAR], - [v_jitstate, c_fielddesc, v_argbox, c_resulttype], + [ts.s_JITState, s_fielddesc, ts.s_RedBox], + [v_jitstate, c_fielddesc, v_argbox ], ts.s_RedBox) @@ -344,7 +335,7 @@ def create(self, hop): if self.typedesc is None: T = self.original_concretetype.TO - self.typedesc = rtimeshift.ContainerTypeDesc(T) + self.typedesc = rtimeshift.ContainerTypeDesc.make(T) ts = self.timeshifter return hop.llops.genmixlevelhelpercall(self.typedesc.ll_factory, [], [], ts.s_RedBox) Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Mon Mar 27 19:48:58 2006 @@ -1,4 +1,4 @@ -import operator +import operator, weakref from pypy.rpython.lltypesystem import lltype, lloperation, llmemory from pypy.rpython import rgenop @@ -33,12 +33,12 @@ return False # generic implementation of some operations - def op_getfield(self, jitstate, fielddesc, gv_resulttype): + def op_getfield(self, jitstate, fielddesc): op_args = lltype.malloc(VARLIST.TO, 2) op_args[0] = self.getgenvar(jitstate) op_args[1] = fielddesc.gv_fieldname genvar = rgenop.genop(jitstate.curblock, 'getfield', op_args, - gv_resulttype) + fielddesc.gv_resulttype) return VarRedBox(genvar) def op_setfield(self, jitstate, fielddesc, valuebox): @@ -91,7 +91,14 @@ "A red box that contains (for now) a virtual Struct." def __init__(self, typedesc): - self.content_boxes = typedesc.content_boxes[:] + # duplicate the list 'content_boxes', + # and also replace the nested VirtualRedBox + clist = [] + for box in typedesc.content_boxes: + if isinstance(box, VirtualRedBox): + box = VirtualRedBox(box.typedesc) + clist.append(box) + self.content_boxes = clist self.typedesc = typedesc self.genvar = rgenop.nullvar @@ -109,9 +116,9 @@ boxes[i]) return self.genvar - def op_getfield(self, jitstate, fielddesc, gv_returntype): + def op_getfield(self, jitstate, fielddesc): if self.content_boxes is None: - return RedBox.op_getfield(self, jitstate, fielddesc, gv_returntype) + return RedBox.op_getfield(self, jitstate, fielddesc) else: return self.content_boxes[fielddesc.fieldindex] @@ -256,22 +263,36 @@ return VarRedBox(genvar) class ContainerTypeDesc(object): + _type_cache = weakref.WeakKeyDictionary() + def __init__(self, TYPE): self.TYPE = TYPE self.PTRTYPE = lltype.Ptr(TYPE) self.gv_type = rgenop.constTYPE(self.TYPE) self.gv_ptrtype = rgenop.constTYPE(self.PTRTYPE) # XXX only for Struct so far - self.fielddescs = [make_fielddesc(self.PTRTYPE, name) + self.fielddescs = [StructFieldDesc.make(self.PTRTYPE, name) for name in TYPE._names] defls = [] for name in TYPE._names: FIELDTYPE = TYPE._flds[name] - defaultvalue = FIELDTYPE._defl() - defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) + if isinstance(FIELDTYPE, lltype.ContainerType): + subtypedesc = ContainerTypeDesc.make(FIELDTYPE) + defaultbox = VirtualRedBox(subtypedesc) + else: + defaultvalue = FIELDTYPE._defl() + defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) defls.append(defaultbox) self.content_boxes = defls + def make(T): + try: + return ContainerTypeDesc._type_cache[T] + except KeyError: + desc = ContainerTypeDesc._type_cache[T] = ContainerTypeDesc(T) + return desc + make = staticmethod(make) + def ll_factory(self): return VirtualRedBox(self) @@ -281,39 +302,57 @@ def compact_repr(self): # goes in ll helper names return "Desc_%s" % (self.TYPE._short_name(),) -class FieldDesc(object): # xxx should we use offsets instead - def __init__(self, PTRTYPE, fieldname): +class FieldDesc(object): + _fielddesc_cache = weakref.WeakKeyDictionary() + + def __init__(self, PTRTYPE, RESTYPE): self.PTRTYPE = PTRTYPE + if isinstance(RESTYPE, lltype.ContainerType): + RESTYPE = lltype.Ptr(RESTYPE) + self.RESTYPE = RESTYPE + self.gv_resulttype = rgenop.constTYPE(RESTYPE) self.immutable = PTRTYPE.TO._hints.get('immutable', False) - self.fieldname = fieldname - self.gv_fieldname = rgenop.constFieldName(fieldname) - if isinstance(PTRTYPE.TO, lltype.Struct): - try: - self.fieldindex = operator.indexOf(PTRTYPE.TO._names, fieldname) - except ValueError: - raise ValueError("field not found: %r in %r" % (fieldname, - PTRTYPE.TO)) def _freeze_(self): return True + def make(cls, PTRTYPE, *args): + T = PTRTYPE.TO + cache = FieldDesc._fielddesc_cache.setdefault(T, {}) + try: + return cache[args] + except KeyError: + fdesc = cache[args] = cls(PTRTYPE, *args) + return fdesc + make = classmethod(make) + +class StructFieldDesc(FieldDesc): + def __init__(self, PTRTYPE, fieldname): + assert isinstance(PTRTYPE.TO, lltype.Struct) + RES1 = getattr(PTRTYPE.TO, fieldname) + FieldDesc.__init__(self, PTRTYPE, RES1) + self.fieldname = fieldname + self.gv_fieldname = rgenop.constFieldName(fieldname) + self.fieldindex = operator.indexOf(PTRTYPE.TO._names, fieldname) + if isinstance(RES1, lltype.ContainerType): + # inlined substructure + self.inlined_typedesc = ContainerTypeDesc.make(RES1) + else: + self.inlined_typedesc = None + def compact_repr(self): # goes in ll helper names return "Fld_%s_in_%s" % (self.fieldname, self.PTRTYPE._short_name()) -_fielddesc_cache = {} - -def make_fielddesc(PTRTYPE, fieldname): - try: - return _fielddesc_cache[PTRTYPE, fieldname] - except KeyError: - fdesc = _fielddesc_cache[PTRTYPE, fieldname] = FieldDesc(PTRTYPE, fieldname) - return fdesc +class ArrayFieldDesc(FieldDesc): + def __init__(self, PTRTYPE): + assert isinstance(PTRTYPE.TO, lltype.Array) + FieldDesc.__init__(self, PTRTYPE, PTRTYPE.TO.OF) -def ll_generate_getfield(jitstate, fielddesc, argbox, gv_resulttype): +def ll_generate_getfield(jitstate, fielddesc, argbox): if fielddesc.immutable and isinstance(argbox, ConstRedBox): res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) return ConstRedBox.ll_fromvalue(res) - return argbox.op_getfield(jitstate, fielddesc, gv_resulttype) + return argbox.op_getfield(jitstate, fielddesc) gv_Void = rgenop.constTYPE(lltype.Void) @@ -321,7 +360,7 @@ destbox.op_setfield(jitstate, fielddesc, valuebox) -def ll_generate_getsubstruct(jitstate, fielddesc, argbox, gv_resulttype): +def ll_generate_getsubstruct(jitstate, fielddesc, argbox): if isinstance(argbox, ConstRedBox): res = getattr(argbox.ll_getvalue(fielddesc.PTRTYPE), fielddesc.fieldname) return ConstRedBox.ll_fromvalue(res) @@ -329,12 +368,11 @@ op_args[0] = argbox.getgenvar(jitstate) op_args[1] = fielddesc.gv_fieldname genvar = rgenop.genop(jitstate.curblock, 'getsubstruct', op_args, - gv_resulttype) + fielddesc.gv_resulttype) return VarRedBox(genvar) -def ll_generate_getarrayitem(jitstate, fielddesc, argbox, - indexbox, gv_resulttype): +def ll_generate_getarrayitem(jitstate, fielddesc, argbox, indexbox): if (fielddesc.immutable and isinstance(argbox, ConstRedBox) and isinstance(indexbox, ConstRedBox)): res = argbox.ll_getvalue(fielddesc.PTRTYPE)[indexbox.ll_getvalue(lltype.Signed)] @@ -343,7 +381,7 @@ op_args[0] = argbox.getgenvar(jitstate) op_args[1] = indexbox.getgenvar(jitstate) genvar = rgenop.genop(jitstate.curblock, 'getarrayitem', op_args, - gv_resulttype) + fielddesc.gv_resulttype) return VarRedBox(genvar) ##def ll_generate_malloc(jitstate, gv_type, gv_resulttype): From ericvrp at codespeak.net Mon Mar 27 22:44:18 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Mon, 27 Mar 2006 22:44:18 +0200 (CEST) Subject: [pypy-svn] r25051 - pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi Message-ID: <20060327204418.1451D10073@code0.codespeak.net> Author: ericvrp Date: Mon Mar 27 22:44:17 2006 New Revision: 25051 Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py Log: Greatly simplyfied setup.py by using llvm-config. (you need llvm cvs to use this) Next: (auto)generate ctypes wrapper script using h2xml.py and then offcourse move the functionality of pyllvm over to here. Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp Mon Mar 27 22:44:17 2006 @@ -0,0 +1,25 @@ +#include "llvmcapi.h" + +// llvm includes +#include "llvm/Type.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/Assembly/Parser.h" +#include "llvm/Bytecode/Reader.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/DerivedTypes.h" + +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + + +// c++ includes +#include +#include + + +int testme(int n) { + return n * n; +} Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h Mon Mar 27 22:44:17 2006 @@ -0,0 +1,15 @@ + +#ifndef LLVMCAPI_H +#define LLVMCAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + + int testme(int n); + +#ifdef __cplusplus +}; +#endif + +#endif Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py Mon Mar 27 22:44:17 2006 @@ -0,0 +1,19 @@ +from distutils.core import setup +from distutils.extension import Extension +from os import popen + +cxxflags = popen('llvm-config --cxxflags').readline().split() +ldflags = popen('llvm-config --ldflags').readline().split() +libs = popen('llvm-config --libs all').readline().split() + +opts = dict(name='llvmcapi', + sources=['llvmcapi.cpp'], + libraries=[], + include_dirs =[f[2:] for f in cxxflags if f.startswith('-I')], + library_dirs =[f[2:] for f in ldflags if f.startswith('-L')], + define_macros=[(f[2:], None) for f in cxxflags if f.startswith('-D')], + extra_objects=libs) + +ext_modules = Extension(**opts) + +setup(name=opts['name'], ext_modules=[ext_modules]) From nik at codespeak.net Mon Mar 27 22:55:41 2006 From: nik at codespeak.net (nik at codespeak.net) Date: Mon, 27 Mar 2006 22:55:41 +0200 (CEST) Subject: [pypy-svn] r25052 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060327205541.1FB1810073@code0.codespeak.net> Author: nik Date: Mon Mar 27 22:55:36 2006 New Revision: 25052 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: my tokyo dates. flight booked, hotel pending. Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Mon Mar 27 22:55:36 2006 @@ -14,7 +14,7 @@ Jacob Hall?n Laura Creighton Anders Lehmann 23/4 - 1/5 ? -Niklaus Haldimann +Niklaus Haldimann 20/4 - 1/5 ? Anders Chrigstr?m 22/4 - 30/4 Samuele Pedroni 22/4 - 30/4 ==================== ============== ===================== From tismer at codespeak.net Tue Mar 28 02:07:16 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 28 Mar 2006 02:07:16 +0200 (CEST) Subject: [pypy-svn] r25054 - pypy/dist/pypy/annotation Message-ID: <20060328000716.A409B10079@code0.codespeak.net> Author: tismer Date: Tue Mar 28 02:07:07 2006 New Revision: 25054 Modified: pypy/dist/pypy/annotation/annrpython.py Log: allow for incomplete build_types Modified: pypy/dist/pypy/annotation/annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/annrpython.py (original) +++ pypy/dist/pypy/annotation/annrpython.py Tue Mar 28 02:07:07 2006 @@ -78,7 +78,7 @@ #___ convenience high-level interface __________________ - def build_types(self, function, input_arg_types): + def build_types(self, function, input_arg_types, complete_now=True): """Recursively build annotations about the specific entry point.""" assert isinstance(function, FunctionType), "fix that!" @@ -92,7 +92,7 @@ assert isinstance(flowgraph, annmodel.SomeObject) return flowgraph - return self.build_graph_types(flowgraph, inputcells) + return self.build_graph_types(flowgraph, inputcells, complete_now=complete_now) def annotate_helper(self, function, args_s, policy=None, complete_now=True): args_s = args_s[:] From tismer at codespeak.net Tue Mar 28 02:08:23 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 28 Mar 2006 02:08:23 +0200 (CEST) Subject: [pypy-svn] r25055 - pypy/dist/pypy/rpython Message-ID: <20060328000823.B85B210079@code0.codespeak.net> Author: tismer Date: Tue Mar 28 02:08:21 2006 New Revision: 25055 Modified: pypy/dist/pypy/rpython/rtyper.py Log: registry for classdefs which need to grow a wrapper Modified: pypy/dist/pypy/rpython/rtyper.py ============================================================================== --- pypy/dist/pypy/rpython/rtyper.py (original) +++ pypy/dist/pypy/rpython/rtyper.py Tue Mar 28 02:08:21 2006 @@ -56,6 +56,7 @@ self.class_reprs = {} self.instance_reprs = {} self.pbc_reprs = {} + self.classdefs_with_wrapper = {} self.concrete_calltables = {} self.class_pbc_attributes = {} self.oo_meth_impls = {} @@ -87,6 +88,9 @@ log.info(s) self.crash_on_first_typeerror = True + def add_wrapper(self, clsdef): + self.classdefs_with_wrapper[clsdef] = clsdef + def add_pendingsetup(self, repr): assert isinstance(repr, Repr) if repr in self._seen_reprs_must_call_setup: @@ -531,6 +535,9 @@ def needs_hash_support(self, clsdef): return clsdef in self.annotator.bookkeeper.needs_hash_support + def needs_wrapper(self, clsdef): + return clsdef in self.classdefs_with_wrapper + def getcallable(self, graph): def getconcretetype(v): return self.bindingrepr(v).lowleveltype From tismer at codespeak.net Tue Mar 28 02:09:28 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 28 Mar 2006 02:09:28 +0200 (CEST) Subject: [pypy-svn] r25056 - pypy/dist/pypy/translator/c Message-ID: <20060328000928.233BE10079@code0.codespeak.net> Author: tismer Date: Tue Mar 28 02:09:25 2006 New Revision: 25056 Modified: pypy/dist/pypy/translator/c/funcgen.py Log: small typo in the patch for PyObject Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Tue Mar 28 02:09:25 2006 @@ -608,7 +608,7 @@ self.expr(op.args[0]))) if NEED_OLD_EXTRA_REFS and TYPE == PyObjPtr: - result.append('Py_XINCREF(%s);'%(LOCAL_VAR % op.result.name)) + result.append('Py_XINCREF(%s);'%(LOCALVAR % op.result.name)) return '\t'.join(result) OP_CAST_PTR_TO_ADR = OP_CAST_POINTER @@ -628,7 +628,7 @@ result.append('%s = %s;' % (self.expr(op.result), self.expr(op.args[0]))) if NEED_OLD_EXTRA_REFS and TYPE == PyObjPtr: - result.append('Py_XINCREF(%s);'%(LOCAL_VAR % op.result.name)) + result.append('Py_XINCREF(%s);'%(LOCALVAR % op.result.name)) return '\t'.join(result) def OP_HINT(self, op, err): From tismer at codespeak.net Tue Mar 28 07:27:40 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 28 Mar 2006 07:27:40 +0200 (CEST) Subject: [pypy-svn] r25060 - in pypy/dist/pypy: rpython/lltypesystem translator/c/test Message-ID: <20060328052740.7BC631007A@code0.codespeak.net> Author: tismer Date: Tue Mar 28 07:27:37 2006 New Revision: 25060 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/translator/c/test/test_wrapping.py Log: changes towards chaching the wrapper instance Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Tue Mar 28 07:27:37 2006 @@ -16,7 +16,7 @@ cast_pointer, castable, nullptr, \ RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, \ Array, Char, Void, attachRuntimeTypeInfo, \ - FuncType, Bool, Signed, functionptr, FuncType + FuncType, Bool, Signed, functionptr, FuncType, PyObject from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython import extregistry @@ -328,6 +328,13 @@ self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef, not self.needsgc) self.rbase.setup() + # + # PyObject wrapper support + if (self.rtyper.needs_wrapper(self.classdef) and '_wrapper_' + not in self.rbase.allinstancefields): + fields['_wrapper_'] = 'wrapper', pyobj_repr + llfields.append(('wrapper', Ptr(PyObject))) + if self.needsgc: MkStruct = GcStruct else: @@ -588,9 +595,22 @@ def ll_call_destructor(thang): return 42 # will be mapped +def ll_clear_wrapper(inst): + # Note: we must ensure to enforce creation of this extra field. + # this is done when we set up the instantiators in XXX which module??? + pass # inst.inst___wrapper__ = None + #inst.fields.au = 42 + #setattr(inst, 'inst___wrapper__', None) + #inst.inst___wrapper__ = Ptr(33)#inst.inst___wrapper__ + #p = ll_cast_to_object(inst) + + #inst.inst___wrapper__ = nullptr(PyObject) + #inst.inst_a = 42 + def rtype_destruct_object(hop): - v_any, = hop.inputargs(*hop.args_r) - hop.genop('gc_unprotect', [v_any]) + v, = hop.inputargs(*hop.args_r) + hop.gendirectcall(ll_clear_wrapper, v) + hop.genop('gc_unprotect', [v]) extregistry.register_value(ll_call_destructor, compute_result_annotation=lambda *args:None, Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Tue Mar 28 07:27:37 2006 @@ -30,9 +30,7 @@ global t # allow us to view later t = TranslationContext() do_register(t) - t.buildannotator().build_types(func, get_annotation(func)) - if view: - t.viewcg() + t.buildannotator() rtyper = t.buildrtyper() bk = rtyper.annotator.bookkeeper instantiators = {} @@ -40,10 +38,16 @@ if isinstance(obj, type): cls = obj def make(): - return instantiate(cls) + obj = instantiate(cls) + return obj make.__name__ = cls.__name__ + '__new__' - t.annotator.build_types(make, []) + t.annotator.build_types(make, [], complete_now=False) instantiators[cls] = make + clsdef = bk.getuniqueclassdef(cls) + rtyper.add_wrapper(clsdef) + t.annotator.build_types(func, get_annotation(func)) + if view: + t.viewcg() rtyper.specialize() if view: t.viewcg() @@ -161,8 +165,11 @@ delmonitor = DelMonitor() +class DemoBaseNotExposed(object): + pass + # a trivial class to be exposed -class DemoClass(object): +class DemoClass(DemoBaseNotExposed): def __init__(self, a, b): self.a = a self.b = b @@ -181,6 +188,11 @@ # see if we get things exported with subclassing class DemoSubclass(DemoClass): + def __init__(self, a, b, c): + #super(DemoSubclass, self).__init__(a, b) + DemoClass.__init__(self, b, a) + self.c = c + def demo(self): return float(DemoClass.demo(self)) @@ -230,7 +242,7 @@ def democlass_helper2(a=int, b=int): self = DemoClass(a, b) self.demo() - self2 = DemoSubclass(a, b) + self2 = DemoSubclass(a, b, 42) return self # creating an object, wrapping, unwrapping, call function, check whether __del__ is called From auc at codespeak.net Tue Mar 28 12:04:37 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 28 Mar 2006 12:04:37 +0200 (CEST) Subject: [pypy-svn] r25072 - in pypy/dist/pypy/objspace: . test Message-ID: <20060328100437.9620410080@code0.codespeak.net> Author: auc Date: Tue Mar 28 12:04:35 2006 New Revision: 25072 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: * unify dicts * misc fixes Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Tue Mar 28 12:04:35 2006 @@ -3,6 +3,7 @@ from pypy.interpreter.error import OperationError from pypy.rpython.objectmodel import we_are_translated from pypy.objspace.std.listobject import W_ListObject, W_TupleObject +from pypy.objspace.std.dictobject import W_DictObject USE_COROUTINES = True HAVE_GREENLETS = True @@ -153,7 +154,7 @@ app_uthread = gateway.interp2app(uthread, unwrap_spec=[baseobjspace.ObjSpace, baseobjspace.W_Root, argument.Arguments]) - + #-- VARIABLE --------------------- @@ -247,7 +248,7 @@ #-- PREDICATES -------------------- def is_aliased(space, w_var): # FIXME: this appears to block - if space.is_true(space.is_nb_(w_var.w_bound_to, w_var)): + if space.is_true(space.is_nb_(deref(space, w_var), w_var)): return space.newbool(False) return space.newbool(True) app_is_aliased = gateway.interp2app(is_aliased) @@ -336,28 +337,33 @@ l = len(a_str) - 1 return a_str[l-3:l] +def _sleep(space, w_var, w_barrier): + wait(space, w_var) + bind(space, w_barrier, space.newint(1)) +#app_sleep = gateway.interp2app(sleep) + def wait_two(space, w_1, w_2): """waits until one out of two logic variables becomes bound, then tells which one, with a bias toward the first if both are suddenly bound""" - w_V = newvar(space) - def sleep(space, w_var): - wait(space, w_var) - bind(space, w_V, space.newint(1)) - uthread(sleep, space, w_1) - uthread(sleep, space, w_2) - wait(space, w_V) + w_barrier = newvar(space) + uthread(space, space.wrap(_sleep), + argument.Arguments(space, [w_1, w_barrier])) + uthread(space, space.wrap(_sleep), + argument.Arguments(space, [w_2, w_barrier])) + wait(space, w_barrier) if space.is_true(is_free(space, w_2)): return space.newint(1) return space.newint(2) +app_wait_two = gateway.interp2app(wait_two) #-- BIND ----------------------------- def bind(space, w_var, w_obj): """1. aliasing of unbound variables - 2. assign unbound var to bound var - 3. assign value to self + 2. assign bound var to unbound var + 3. assign value to unbound var """ print " :bind", w_var, w_obj assert isinstance(w_var, W_Var) @@ -367,8 +373,10 @@ return unify(space, deref(space, w_var), deref(space, w_obj)) + # 2. a (obj unbound, var bound) return _assign(space, w_obj, deref(space, w_var)) elif space.is_true(is_bound(space, w_obj)): + # 2. b (var unbound, obj bound) return _assign(space, w_var, deref(space, w_obj)) else: # 1. both are unbound return _alias(space, w_var, w_obj) @@ -422,19 +430,14 @@ w_tail = w_v1.w_bound_to w_v1.w_bound_to = w_v2 w_v2.w_bound_to = w_tail - disp_aliases(space, w_v1) - disp_aliases(space, w_v2) return space.w_None def _merge_aliases(space, w_v1, w_v2): print " :merge aliases", w_v1, w_v2 - # first get the tail of both sets w_tail1 = get_ring_tail(space, w_v1) w_tail2 = get_ring_tail(space, w_v2) w_tail1.w_bound_to = w_v2 w_tail2.w_bound_to = w_v1 - disp_aliases(space, w_v1) - disp_aliases(space, w_v2) return space.w_None #-- UNIFY ------------------------- @@ -454,48 +457,41 @@ return unify(space, deref(space, w_x), w_y) return bind(space, w_x, w_y) # x, y are vars - elif space.is_true(is_bound(space, w_x)) and \ - space.is_true(is_bound(space, w_x)): - return _unify_values(space, - deref(space, w_x), - deref(space, w_y)) elif space.is_true(is_bound(space, w_x)): + if space.is_true(is_bound(space, w_y)): + return _unify_values(space, + deref(space, w_x), + deref(space, w_y)) return bind(space, w_y, w_x) # aliasing x & y ? else: return bind(space, w_x, w_y) # aliasing - #XXX: really do what's below : - #return _unify_unbound(space, w_x, w_y) reset_memo() app_unify = gateway.interp2app(unify) - -def _unify_unbound(space, w_x, w_y): - """sleeps until one of the two is bound - then bind the other to its value""" - w_bound = wait_two(space, w_x, w_y) - if space.eq_w(w_bound, space.newint(1)): - return bind(space, w_y, w_x) - return bind(space, w_x, w_y) - + def _unify_values(space, w_v1, w_v2): - #print " :unify values", w_v1, w_v2 + print " :unify values", w_v1, w_v2 # unify object of the same type ... FIXME if not space.is_w(space.type(w_v1), space.type(w_v2)): fail(space, w_v1, w_v2) # ... elements of a list/tuple ... - if isinstance(w_v1, W_ListObject) or \ - isinstance(w_v1, W_TupleObject): + if (isinstance(w_v1, W_ListObject) and \ + isinstance(w_v2, W_ListObject)) or \ + (isinstance(w_v1, W_TupleObject) and \ + isinstance(w_v1, W_TupleObject)): _unify_iterables(space, w_v1, w_v2) - else: + elif isinstance(w_v1, W_DictObject) and \ + isinstance(w_v1, W_DictObject): + _unify_mappings(space, w_v1, w_v2) # ... token equality if not space.eq_w(w_v1, w_v2): fail(space, w_v1, w_v2) return space.w_None def _unify_iterables(space, w_i1, w_i2): - #print " :unify iterables", w_i1, w_i2 + print " :unify iterables", w_i1, w_i2 # assert lengths if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): fail(space, w_i1, w_i2) @@ -509,6 +505,19 @@ continue unify(space, w_xi, w_yi) +def _unify_mappings(space, w_m1, w_m2): + print " :unify mappings", w_m1, w_m2 +## if len(w_m1.wrappeditems) != len(w_m2.wrappeditems): +## fail(space, w_i1, w_i2) + for w_xk in w_m1.content.keys(): + w_xi = space.getitem(w_m1, w_xk) + w_yi = space.getitem(w_m2, w_xk) + if space.is_true(space.is_nb_(w_xi, w_yi)): + continue + unify(space, w_xi, w_yi) + + + # multimethod version of unify ## def unify__W_Var_W_Var(space, w_v1, w_v2): ## return bind(space, w_v1, w_v2) @@ -685,6 +694,8 @@ space.wrap(app_uthread)) space.setitem(space.builtin.w_dict, space.wrap('wait'), space.wrap(app_wait)) +## space.setitem(space.builtin.w_dict, space.wrap('wait_two'), +## space.wrap(app_wait_two)) space.setitem(space.builtin.w_dict, space.wrap('wait_needed'), space.wrap(app_wait_needed)) return space Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Tue Mar 28 12:04:35 2006 @@ -20,15 +20,12 @@ # FailureException raises(Exception, bind, X, 2) - def test_unify_tuple(self): - X = newvar() - unify(X, (1, (2, None))) - assert X == (1, (2, None)) - def test_bind_to_self(self): X = newvar() assert is_free(X) bind(X, X) + assert is_free(X) + assert alias_of(X, X) bind(X, 1) assert X == 1 @@ -36,19 +33,17 @@ X = newvar() assert is_free(X) unify(X, X) + assert is_free(X) + assert alias_of(X, X) unify(X, 1) assert X == 1 - def test_unify_alias(self): - X = newvar() - Y = newvar() - unify(X, Y) - assert alias_of(X, Y) - assert alias_of(Y, X) - bind(X, 1) - # what about is_alias, then ? - assert X == 1 - assert Y == 1 + def test_unify_circular(self): + X, Y = newvar(), newvar() + unify(X, [Y]) + unify(Y, [X]) + assert X == [Y] + assert Y == [X] def test_unify_alias(self): X = newvar() @@ -142,7 +137,7 @@ def test_eq_unifies_simple(self): X = newvar() Y = newvar() - unify(X, Y) + bind(X, Y) assert alias_of(Y, X) unify(X, 1) assert X == 1 @@ -154,13 +149,18 @@ def test_ne_of_unified_unbound_vars(self): X = newvar() Y = newvar() - unify(X, Y) + bind(X, Y) assert is_free(X) assert is_free(Y) assert alias_of(X, Y) assert X == Y assert not X != Y + def test_unify_tuple(self): + X = newvar() + unify(X, (1, (2, None))) + assert X == (1, (2, None)) + def test_unify_list(self): X = newvar() x = (newvar(), newvar()) @@ -171,8 +171,16 @@ assert X[1] == x[1] unify(X, (1, (2, None))) assert X == (1, (2, None)) + unify(X, (1, (2, None))) raises(Exception, unify, X, (1, 2)) + def test_unify_dict(self): + Z, W = newvar(), newvar() + unify({'a': 42, 'b': Z}, + {'a': Z, 'b': W}) + assert Z == W == 42 + + class AppTest_LogicThreads(object): def setup_class(cls): @@ -197,13 +205,13 @@ def test_eager_producer_consummer(self): def generate(n, limit): - print "generate", n, limit + #print "generate", n, limit if n < limit: return (n, generate(n + 1, limit)) return None def sum(L, a): - print "sum", a + #print "sum", a Head, Tail = newvar(), newvar() unify(L, (Head, Tail)) if Tail != None: @@ -213,7 +221,7 @@ X = newvar() S = newvar() - bind(S, uthread(sum, X, 0)) + unify(S, uthread(sum, X, 0)) unify(X, uthread(generate, 0, 10)) assert S == 45 @@ -223,35 +231,52 @@ def lgenerate(n, L): """wait-needed version of generate""" - print "-- generator waits on L being needed" wait_needed(L) Tail = newvar() bind(L, (n, Tail)) - print "generator bound L" lgenerate(n+1, Tail) def lsum(L, a, limit): """this summer controls the generator""" if limit > 0: - print "sum : ", a Head, Tail = newvar(), newvar() - print "-- sum waiting on L" wait(L) unify(L, (Head, Tail)) return lsum(Tail, a+Head, limit-1) else: return a - print "lazy producer consummer" - print "before" Y = newvar() T = newvar() - disp(Y) - disp(T) + uthread(lgenerate, 0, Y) unify(T, uthread(lsum, Y, 0, 10)) - print "after" wait(T) assert T == 45 - print T + + def notest_wait_two(self): + def sleep(X, Barrier): + print "sleep" + wait(X) + bind(Barrier, True) + + def wait_two(X, Y): + print "wait two" + Z = newvar() + uthread(sleep, X, Z) + uthread(sleep, Y, Z) + print "on barrier" + wait(Z) + if is_free(Y): + return 1 + return 2 + + X, Y = newvar(), newvar() + disp(X) + disp(Y) + o = uthread(wait_two, X, Y) + unify(X, Y) + unify(Y, 42) + assert X == Y == 42 + assert o == 2 From antocuni at codespeak.net Tue Mar 28 12:21:04 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 28 Mar 2006 12:21:04 +0200 (CEST) Subject: [pypy-svn] r25073 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060328102104.E883210082@code0.codespeak.net> Author: antocuni Date: Tue Mar 28 12:20:28 2006 New Revision: 25073 Added: pypy/dist/pypy/translator/cli/option.py (contents, props changed) Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/gencli.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/runtest.py Log: Added file option.py that I have forgotten last time. Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Tue Mar 28 12:20:28 2006 @@ -4,7 +4,7 @@ from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong -from pypy.translator.cli.options import getoption +from pypy.translator.cli.option import getoption from pypy.tool.ansi_print import ansi_log import py Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Mar 28 12:20:28 2006 @@ -1,6 +1,6 @@ from pypy.objspace.flow import model as flowmodel from pypy.rpython.lltypesystem.lltype import Void -from pypy.translator.cli.options import getoption +from pypy.translator.cli.option import getoption from pypy.translator.cli import cts from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs Modified: pypy/dist/pypy/translator/cli/gencli.py ============================================================================== --- pypy/dist/pypy/translator/cli/gencli.py (original) +++ pypy/dist/pypy/translator/cli/gencli.py Tue Mar 28 12:20:28 2006 @@ -3,7 +3,7 @@ from pypy.translator.cli import conftest from pypy.translator.cli.ilgenerator import IlasmGenerator from pypy.translator.cli.function import Function -from pypy.translator.cli.options import getoption +from pypy.translator.cli.option import getoption class Tee(object): Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Tue Mar 28 12:20:28 2006 @@ -37,8 +37,7 @@ 'int_add': 'add', 'int_sub': 'sub', 'int_mul': 'mul', - 'int_div': 'div', - 'int_truediv': None, # TODO +# 'int_div': 'div', 'int_floordiv': 'div', 'int_mod': 'rem', 'int_lt': 'clt', @@ -104,9 +103,9 @@ 'float_add': 'add', 'float_sub': 'sub', 'float_mul': 'mul', - 'float_div': 'div', +# 'float_div': 'div', 'float_truediv': 'div', - 'float_floordiv': None, # TODO +# 'float_floordiv': None, # TODO 'float_mod': 'rem', 'float_lt': 'clt', 'float_le': _not('cgt'), Added: pypy/dist/pypy/translator/cli/option.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/option.py Tue Mar 28 12:20:28 2006 @@ -0,0 +1,6 @@ +from pypy.translator.cli.conftest import option + +_defaultopt = dict(wd = False, source = False, nostop = False, stdout = False) + +def getoption(name): + return getattr(option, name, _defaultopt.get(name)) Modified: pypy/dist/pypy/translator/cli/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/runtest.py (original) +++ pypy/dist/pypy/translator/cli/test/runtest.py Tue Mar 28 12:20:28 2006 @@ -5,7 +5,7 @@ import py from pypy.tool.udir import udir from pypy.translator.translator import TranslationContext -from pypy.translator.cli.options import getoption +from pypy.translator.cli.option import getoption from pypy.translator.cli.gencli import GenCli from pypy.translator.cli.function import Node from pypy.translator.cli.cts import graph_to_signature From nico at codespeak.net Tue Mar 28 12:38:31 2006 From: nico at codespeak.net (nico at codespeak.net) Date: Tue, 28 Mar 2006 12:38:31 +0200 (CEST) Subject: [pypy-svn] r25075 - pypy/dist/pypy/doc Message-ID: <20060328103831.C03E610082@code0.codespeak.net> Author: nico Date: Tue Mar 28 12:38:30 2006 New Revision: 25075 Modified: pypy/dist/pypy/doc/events.txt pypy/dist/pypy/doc/news.txt Log: added presence at french XP Day Modified: pypy/dist/pypy/doc/events.txt ============================================================================== --- pypy/dist/pypy/doc/events.txt (original) +++ pypy/dist/pypy/doc/events.txt Tue Mar 28 12:38:30 2006 @@ -29,9 +29,3 @@ .. _`the announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-announcement.html .. _`People page`: http://codespeak.net/svn/pypy/extradoc/sprintinfo/tokyo/people.txt -Sprint in Tokyo (Japan) -=================================================================== - -*April 23rd - April 29th 2006.* - - Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Tue Mar 28 12:38:30 2006 @@ -20,6 +20,16 @@ .. _`the sprint announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-announcement.html .. _`people page`: http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/people.html +PyPy at XPDay France 2006 in Paris March 23rd - March 24th 2006 +================================================================== + +Logilab presented PyPy at the first `french XP Day`_ that it was +sponsoring and which was held in Paris. There was over a hundred +attendants. Interesting talks included Python as an agile language and +Tools for continuous integration. + +.. _`french XP Day`: http://www.xpday.fr/ + Logic Sprint at Louvain-la-Neuve University (Louvain-la-Neuve, Belgium) ======================================================================== From ericvrp at codespeak.net Tue Mar 28 13:12:37 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Tue, 28 Mar 2006 13:12:37 +0200 (CEST) Subject: [pypy-svn] r25076 - pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi Message-ID: <20060328111237.10A8610082@code0.codespeak.net> Author: ericvrp Date: Tue Mar 28 13:12:35 2006 New Revision: 25076 Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/cc.py pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.sh (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h Log: Example (create_pyllvm.sh) that creates the ctypes wrapper code to interface with a C shared library (llvmcapi.so). The wrapper is generated using ctypes codegenerator (that depends on gccxml). llvmcapi.so is generated by setup.py (CPython distutils) note: pyllvm.py is added for ease of use. It can be reconstructed, but at least this way not everyone has to install gccxml. Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/cc.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/cc.py Tue Mar 28 13:12:35 2006 @@ -0,0 +1,16 @@ +''' +Added this because ctypes on my computer was missing cdecl. +''' +from ctypes import * + +class cdecl(object): + def __init__(self, restype, libname, argtypes): + self.library = cdll.load(libname + ".so") + self.restype = restype + self.argtypes = argtypes + + def __call__(self, func): + func._api_ = getattr(self.library, func.__name__) + func._api_.restype = self.restype + func._api_.argtypes = self.argtypes + return func Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.sh ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.sh Tue Mar 28 13:12:35 2006 @@ -0,0 +1,11 @@ +#!/bin/bash + +python setup.py build_ext -i -q + +if [ -f ~/projects/ctypes/ctypes/wrap/h2xml.py ] +then + python ~/projects/ctypes/ctypes/wrap/h2xml.py llvmcapi.h -q -I . -o llvmcapi.xml + python ~/projects/ctypes/ctypes/wrap/xml2py.py llvmcapi.xml -l llvmcapi.so -o pyllvm.tmp + sed -e s/from\ ctypes\ import/from\ cc\ import/ pyllvm.tmp > pyllvm.py + rm -f pyllvm.tmp llvmcapi.xml +fi Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp Tue Mar 28 13:12:35 2006 @@ -20,6 +20,10 @@ #include -int testme(int n) { +int testme1(int n) { return n * n; } + +float testme2(float f) { + return f * f; +} Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h Tue Mar 28 13:12:35 2006 @@ -6,7 +6,8 @@ extern "C" { #endif - int testme(int n); +int testme1(int n); +float testme2(float f); #ifdef __cplusplus }; Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py Tue Mar 28 13:12:35 2006 @@ -0,0 +1,17 @@ +# generated by 'xml2py' +# flags 'llvmcapi.xml -l llvmcapi.so -o pyllvm.tmp' +from cc import * + + + +def testme1(n): + # llvmcapi.h 9 + return testme1._api_(n) +testme1 = cdecl(c_int, 'llvmcapi', [c_int]) (testme1) + + +def testme2(f): + # llvmcapi.h 10 + return testme2._api_(f) +testme2 = cdecl(c_float, 'llvmcapi', [c_float]) (testme2) + From auc at codespeak.net Tue Mar 28 14:08:12 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 28 Mar 2006 14:08:12 +0200 (CEST) Subject: [pypy-svn] r25082 - in pypy/dist/pypy/objspace: . test Message-ID: <20060328120812.D647210082@code0.codespeak.net> Author: auc Date: Tue Mar 28 14:08:11 2006 New Revision: 25082 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: unification of instances Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Tue Mar 28 14:08:11 2006 @@ -471,7 +471,7 @@ def _unify_values(space, w_v1, w_v2): - print " :unify values", w_v1, w_v2 + print " :unify values", w_v1, w_v2 # unify object of the same type ... FIXME if not space.is_w(space.type(w_v1), space.type(w_v2)): @@ -481,17 +481,24 @@ isinstance(w_v2, W_ListObject)) or \ (isinstance(w_v1, W_TupleObject) and \ isinstance(w_v1, W_TupleObject)): - _unify_iterables(space, w_v1, w_v2) + return _unify_iterables(space, w_v1, w_v2) elif isinstance(w_v1, W_DictObject) and \ isinstance(w_v1, W_DictObject): - _unify_mappings(space, w_v1, w_v2) + return _unify_mappings(space, w_v1, w_v2) # ... token equality - if not space.eq_w(w_v1, w_v2): - fail(space, w_v1, w_v2) - return space.w_None + if not space.eq_w(w_v1, w_v2): + return _unify_instances(space, w_v1, w_v2) + #fail(space, w_v1, w_v2) + return space.w_None + +def _unify_instances(space, w_i1, w_i2): + print " :unify instances" + return _unify_mappings(space, + w_i1.getdict(), + w_i2.getdict()) def _unify_iterables(space, w_i1, w_i2): - print " :unify iterables", w_i1, w_i2 + print " :unify iterables", w_i1, w_i2 # assert lengths if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): fail(space, w_i1, w_i2) @@ -506,7 +513,7 @@ unify(space, w_xi, w_yi) def _unify_mappings(space, w_m1, w_m2): - print " :unify mappings", w_m1, w_m2 + print " :unify mappings", w_m1, w_m2 ## if len(w_m1.wrappeditems) != len(w_m2.wrappeditems): ## fail(space, w_i1, w_i2) for w_xk in w_m1.content.keys(): Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Tue Mar 28 14:08:11 2006 @@ -181,6 +181,21 @@ assert Z == W == 42 + def test_unify_instances(self): + class Foo(object): + def __init__(self, a): + self.a = a + self.b = newvar() + + f1 = Foo(newvar()) + f2 = Foo(42) + unify(f1, f2) + assert f1.a == f2.a == 42 + assert alias_of(f1.b, f2.b) + unify(f2.b, 'foo') + assert f1.b == f2.b == 'foo' + + class AppTest_LogicThreads(object): def setup_class(cls): From bea at codespeak.net Tue Mar 28 14:37:14 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Tue, 28 Mar 2006 14:37:14 +0200 (CEST) Subject: [pypy-svn] r25083 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060328123714.996C21007D@code0.codespeak.net> Author: bea Date: Tue Mar 28 14:37:13 2006 New Revision: 25083 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: My arrival/departure dates (I have to leave on the 25th since we are flying back with my mother in law on the 26th) As said in pypy-sync meeting - please fill out if you are coming or not....Christian, Holger...others? Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Tue Mar 28 14:37:13 2006 @@ -8,7 +8,7 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== -Beatrice D?ring +Beatrice D?ring 21/4-25/4 Christian Tismer Eric van Riet Paap Jacob Hall?n From antocuni at codespeak.net Tue Mar 28 17:37:42 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 28 Mar 2006 17:37:42 +0200 (CEST) Subject: [pypy-svn] r25086 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060328153742.E6DCC1009A@code0.codespeak.net> Author: antocuni Date: Tue Mar 28 17:37:30 2006 New Revision: 25086 Added: pypy/dist/pypy/translator/cli/test/test_overflow.py (contents, props changed) Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/compile.py Log: Added support for exception handling in generated code. Added initial support for overflow checking Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Tue Mar 28 17:37:30 2006 @@ -2,8 +2,11 @@ Translate between PyPy ootypesystem and .NET Common Type System """ +import exceptions + from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong +from pypy.rpython.ootypesystem.ootype import Instance from pypy.translator.cli.option import getoption from pypy.tool.ansi_print import ansi_log @@ -31,29 +34,29 @@ 'float64': 'r8', } -def lltype_to_cts(t): +def _get_from_dict(d, key, error): try: - return _lltype_to_cts[t] + return d[key] except KeyError: if getoption('nostop'): - log.WARNING('Unknown type %s' % t) - return t + log.WARNING(error) + return key else: - assert False, 'Unknown type %s' % t + assert False, error + + +def lltype_to_cts(t): + # TODO: handle instances more accurately + if isinstance(t, Instance): + return 'object' + + return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t) def lltype_to_ilasm(t): return ctstype_to_ilasm(lltype_to_cts(t)) def ctstype_to_ilasm(t): - try: - return _cts_to_ilasm[t] - except KeyError: - if getoption('nostop'): - log.WARNING('Unknown ilasm type %s' % t) - return t - else: - assert False, 'Unknown ilasm type %s' % t - + return _get_from_dict(_cts_to_ilasm, t, 'Unknown ilasm type %s' % t) def llvar_to_cts(var): return lltype_to_cts(var.concretetype), var.name @@ -80,3 +83,11 @@ arg_list = ', '.join(arg_types) return '%s %s(%s)' % (ret_type, func_name, arg_list) + +_pyexception_to_cts = { + exceptions.Exception: '[mscorlib]System.Exception', + exceptions.OverflowError: '[mscorlib]System.OverflowException' + } + +def pyexception_to_cts(exc): + return _get_from_dict(_pyexception_to_cts, exc, 'Unknown exception %s' % exc) Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Mar 28 17:37:30 2006 @@ -23,50 +23,93 @@ self.graph = graph self.is_entrypoint = is_entrypoint self.blocknum = {} - self._set_args() self._set_locals() def get_name(self): return self.graph.name + def _is_return_block(self, block): + return (not block.exits) and len(block.inputargs) == 1 + + def _is_raise_block(self, block): + return (not block.exits) and len(block.inputargs) == 2 + def render(self, ilasm): self.ilasm = ilasm graph = self.graph returntype, returnvar = cts.llvar_to_cts(graph.getreturnvar()) - ilasm.begin_function(graph.name, self.args, returntype, self.is_entrypoint) - ilasm.locals(self.locals) + self.ilasm.begin_function(graph.name, self.args, returntype, self.is_entrypoint) + self.ilasm.locals(self.locals) for block in graph.iterblocks(): - ilasm.label(self._get_block_name(block)) + self.ilasm.label(self._get_block_name(block)) + + handle_exc = (block.exitswitch == flowmodel.c_last_exception) + if handle_exc: + self.ilasm.begin_try() for op in block.operations: self._render_op(op) - # if it is the last block, return the result - if not block.exits: - assert len(block.inputargs) == 1 + # check for codeless blocks + if self._is_return_block(block): return_var = block.inputargs[0] if return_var.concretetype is not Void: self._push(return_var) - ilasm.opcode('ret') + self.ilasm.opcode('ret') + elif self._is_raise_block(block): + exc = block.inputargs[1] + self._push(exc) + self.ilasm.opcode('throw') + + if handle_exc: + # search for the "default" block to be executed when no exception is raised + for link in block.exits: + if link.exitcase is None: + self._setup_link(link) + target_label = self._get_block_name(link.target) + self.ilasm.leave(target_label) + self.ilasm.end_try() + + # catch the exception and dispatch to the appropriate block + for link in block.exits: + if link.exitcase is None: + continue # see above + + assert issubclass(link.exitcase, Exception) + cts_exc = cts.pyexception_to_cts(link.exitcase) + self.ilasm.begin_catch(cts_exc) + + target = link.target + if self._is_raise_block(target): + # the exception value is on the stack, use it as the 2nd target arg + assert len(link.args) == 2 + assert len(target.inputargs) == 2 + self._store(link.target.inputargs[1]) + else: + # pop the unused exception value + self.ilasm.opcode('pop') + self._setup_link(link) + + target_label = self._get_block_name(target) + self.ilasm.leave(target_label) + self.ilasm.end_catch() + + else: + # no exception handling, follow block links + for link in block.exits: + self._setup_link(link) + target_label = self._get_block_name(link.target) + if link.exitcase is None: + self.ilasm.branch(target_label) + else: + assert type(link.exitcase is bool) + assert block.exitswitch is not None + self._push(block.exitswitch) + self.ilasm.branch_if(link.exitcase, target_label) - # follow block links - for link in block.exits: - target = link.target - for to_load, to_store in zip(link.args, target.inputargs): - if to_load.concretetype is not Void: - self._push(to_load) - self._store(to_store) - - target_label = self._get_block_name(target) - if link.exitcase is None: - self.ilasm.branch(target_label) - else: - assert type(link.exitcase is bool) - self._push(block.exitswitch) - self.ilasm.branch_if(link.exitcase, target_label) # add a block that will never be executed, just to please the # .NET runtime that seems to need a return statement at the @@ -76,8 +119,15 @@ self.ilasm.opcode('ldc.%s 0' % ilasm_type) self.ilasm.opcode('ret') - - ilasm.end_function() + self.ilasm.end_function() + + def _setup_link(self, link): + target = link.target + for to_load, to_store in zip(link.args, target.inputargs): + if to_load.concretetype is not Void: + self._push(to_load) + self._store(to_store) + def _set_locals(self): # this code is partly borrowed from pypy.translator.c.funcgen.FunctionCodeGenerator @@ -187,6 +237,7 @@ def _store(self, v): if isinstance(v, flowmodel.Variable): - self.ilasm.opcode('stloc', repr(v.name)) + if v.concretetype is not Void: + self.ilasm.opcode('stloc', repr(v.name)) else: assert False Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Tue Mar 28 17:37:30 2006 @@ -56,6 +56,20 @@ def end_function(self): self.code.closeblock() + def begin_try(self): + self.code.writeline('.try') + self.code.openblock() + + def end_try(self): + self.code.closeblock() + + def begin_catch(self, type_): + self.code.writeline('catch ' + type_) + self.code.openblock() + + def end_catch(self): + self.code.closeblock() + def locals(self, vars): varlist = ', '.join(['%s %s' % var for var in vars]) self.code.write('.locals init (') @@ -67,6 +81,9 @@ self.code.write(lbl + ':', indent=0) self.code.writeline() + def leave(self, lbl): + self.code.writeline('leave ' + lbl) + def branch(self, lbl): self.code.writeline('br ' + lbl) Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Tue Mar 28 17:37:30 2006 @@ -51,11 +51,10 @@ 'int_lshift': 'shl', 'int_rshift': 'shr', 'int_xor': 'xor', - 'int_add_ovf': None, - 'int_sub_ovf': None, - 'int_mul_ovf': None, - 'int_div_ovf': None, - 'int_truediv_ovf': None, + 'int_add_ovf': 'add.ovf', + 'int_sub_ovf': 'sub.ovf', + 'int_mul_ovf': 'mul.ovf', +# 'int_div_ovf': None, 'int_floordiv_ovf': None, 'int_mod_ovf': None, 'int_lt_ovf': None, Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Tue Mar 28 17:37:30 2006 @@ -24,37 +24,23 @@ print 'OK' -def foo(x): - pass - -def xxx(): +def foo(): pass def bar(x, y): try: - foo(x) - z = ovfcheck(x+y) - xxx() - return z + foo() + z = x except OverflowError: - while x: - x = x-1 - return x - except IndexError: - return 52 - + z = x+y + + return z -def bar(x, y): - foo(x) - foo(None) f = compile_function(bar, [int, int]) try: - check(f, bar, r_uint(sys.maxint+1), r_uint(42)) - check(f, bar, 4, 5) + pass except py.test.Item.Skipped: print 'Test skipped' - -#compile_function(s.is_perfect_number, [int]) Added: pypy/dist/pypy/translator/cli/test/test_overflow.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/test/test_overflow.py Tue Mar 28 17:37:30 2006 @@ -0,0 +1,27 @@ +from pypy.translator.cli.test.runtest import check +from pypy.rpython.rarithmetic import ovfcheck + +import sys + +def op_add(x, y): + try: + return ovfcheck(x+y) + except OverflowError: + return 42 + +def op_sub(x, y): + try: + return ovfcheck(x-y) + except OverflowError: + return 42 + +def op_mul(x, y): + try: + return ovfcheck(x*y) + except OverflowError: + return 42 + +def test_overflow(): + yield check, op_add, [int, int], (sys.maxint, 1) + yield check, op_sub, [int, int], (-sys.maxint, 1) + yield check, op_mul, [int, int], (sys.maxint/2 + 1, 2) From auc at codespeak.net Tue Mar 28 19:09:56 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Tue, 28 Mar 2006 19:09:56 +0200 (CEST) Subject: [pypy-svn] r25087 - in pypy/dist/pypy/objspace: . test Message-ID: <20060328170956.8C9761008A@code0.codespeak.net> Author: auc Date: Tue Mar 28 19:09:54 2006 New Revision: 25087 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: hack to get multimethods from logic space Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Tue Mar 28 19:09:54 2006 @@ -660,10 +660,55 @@ return proxy + + +from pypy.objspace.std.model import StdObjSpaceMultiMethod +from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.floatobject import W_FloatObject +from pypy.objspace.std import stdtypedef +from pypy.tool.sourcetools import func_with_new_name + +def foo__Int_Int(space, w_a, w_b): + print "i'm foo int int" + +def foo__Int_Float(space, w_a, w_b): + print "i'm foo int float" + +def foo__Float_Int(space, w_a, w_b): + space.foo(w_b, w_a) + + +foo_mm = StdObjSpaceMultiMethod('foo', 2) +foo_mm.register(foo__Int_Int, W_IntObject, W_IntObject) +foo_mm.register(foo__Int_Float, W_IntObject, W_FloatObject) +foo_mm.register(foo__Float_Int, W_FloatObject, W_IntObject) + +def my_foo(space, w_1, w_2): + space.foo(w_1, w_2) +app_foo = gateway.interp2app(my_foo) + def Space(*args, **kwds): # for now, always make up a wrapped StdObjSpace from pypy.objspace import std space = std.Space(*args, **kwds) + + # multimethods hack + name = 'foo' + exprargs, expr, miniglobals, fallback = ( + foo_mm.install_not_sliced(space.model.typeorder, baked_perform_call=False)) + func = stdtypedef.make_perform_trampoline('__foo_mm_'+name, + exprargs, expr, miniglobals, + foo_mm) + # e.g. add(space, w_x, w_y) + def make_boundmethod(func=func): + def boundmethod(*args): + return func(space, *args) + return func_with_new_name(boundmethod, 'boundmethod_'+name) + boundmethod = make_boundmethod() + setattr(space, name, boundmethod) # store into 'space' instance + # /multimethod hack + + is_nb_ = space.is_ # capture the original is_ op (?) patch_space_in_place(space, 'logic', proxymaker) space.is_nb_ = is_nb_ @@ -683,6 +728,8 @@ space.wrap(app_bind)) space.setitem(space.builtin.w_dict, space.wrap('unify'), space.wrap(app_unify)) + space.setitem(space.builtin.w_dict, space.wrap('foo'), + space.wrap(app_foo)) if USE_COROUTINES: import os def exitfunc(): @@ -701,8 +748,7 @@ space.wrap(app_uthread)) space.setitem(space.builtin.w_dict, space.wrap('wait'), space.wrap(app_wait)) -## space.setitem(space.builtin.w_dict, space.wrap('wait_two'), -## space.wrap(app_wait_two)) space.setitem(space.builtin.w_dict, space.wrap('wait_needed'), space.wrap(app_wait_needed)) return space + Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Tue Mar 28 19:09:54 2006 @@ -195,6 +195,11 @@ unify(f2.b, 'foo') assert f1.b == f2.b == 'foo' + def test_foo(self): + foo(1, 2) + foo(1, 2.0) + foo(2.0, 1) + class AppTest_LogicThreads(object): From antocuni at codespeak.net Tue Mar 28 23:18:34 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 28 Mar 2006 23:18:34 +0200 (CEST) Subject: [pypy-svn] r25092 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060328211834.56CF61009F@code0.codespeak.net> Author: antocuni Date: Tue Mar 28 23:18:15 2006 New Revision: 25092 Modified: pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/compile.py pypy/dist/pypy/translator/cli/test/test_op.py pypy/dist/pypy/translator/cli/test/test_overflow.py Log: More overflow support. Added special tests for int_le and int_ge operations Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Mar 28 23:18:15 2006 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem.lltype import Void from pypy.translator.cli.option import getoption from pypy.translator.cli import cts -from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs +from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs, PushArg from pypy.tool.ansi_print import ansi_log import py @@ -206,6 +206,8 @@ if instr is PushArgs: for arg in op.args: self._push(arg) + elif isinstance(instr, PushArg): + self._push(op.args[instr.arg]) else: self.ilasm.opcode(instr) Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Tue Mar 28 23:18:15 2006 @@ -4,6 +4,10 @@ # come useful instruction patterns Not = ['ldc.i4.0', 'ceq'] +class PushArg(object): + def __init__(self, arg): + self.arg = arg + def _not(op): return [PushArgs, op]+Not @@ -55,20 +59,20 @@ 'int_sub_ovf': 'sub.ovf', 'int_mul_ovf': 'mul.ovf', # 'int_div_ovf': None, - 'int_floordiv_ovf': None, - 'int_mod_ovf': None, - 'int_lt_ovf': None, - 'int_le_ovf': None, - 'int_eq_ovf': None, - 'int_ne_ovf': None, - 'int_gt_ovf': None, - 'int_ge_ovf': None, - 'int_and_ovf': None, - 'int_or_ovf': None, - 'int_lshift_ovf': None, - 'int_rshift_ovf': None, - 'int_xor_ovf': None, - 'int_floordiv_ovf_zer': None, + 'int_floordiv_ovf': 'div', # these can't overflow! + 'int_mod_ovf': 'rem', + 'int_lt_ovf': 'clt', + 'int_le_ovf': _not('cgt'), + 'int_eq_ovf': 'ceq', + 'int_ne_ovf': _not('ceq'), + 'int_gt_ovf': 'cgt', + 'int_ge_ovf': _not('clt'), + 'int_and_ovf': 'and', + 'int_or_ovf': 'or', + 'int_lshift_ovf_val': [PushArg(0), 'conv.i8', PushArg(1), 'shl', 'conv.ovf.i4'], + 'int_rshift_ovf': 'shr', # these can't overflow! + 'int_xor_ovf': 'xor', + 'int_floordiv_ovf_zer': None, # what's the meaning? 'int_mod_ovf_zer': None, 'uint_is_true': DoNothing, Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Tue Mar 28 23:18:15 2006 @@ -24,18 +24,11 @@ print 'OK' -def foo(): +def foo(x, y, z): pass def bar(x, y): - try: - foo() - z = x - except OverflowError: - z = x+y - - return z - + foo(x+y, x-y, x*y) f = compile_function(bar, [int, int]) Modified: pypy/dist/pypy/translator/cli/test/test_op.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_op.py (original) +++ pypy/dist/pypy/translator/cli/test/test_op.py Tue Mar 28 23:18:15 2006 @@ -4,6 +4,11 @@ import sys def test_op(): + yield check, op_any_ge, [int, int], (42, 42) + yield check, op_any_ge, [int, int], (13, 42) + yield check, op_any_le, [int, int], (42, 42) + yield check, op_any_le, [int, int], (13, 42) + for name, func in globals().iteritems(): if not name.startswith('op_'): continue Modified: pypy/dist/pypy/translator/cli/test/test_overflow.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_overflow.py (original) +++ pypy/dist/pypy/translator/cli/test/test_overflow.py Tue Mar 28 23:18:15 2006 @@ -21,7 +21,21 @@ except OverflowError: return 42 +def op_lshift(x, y): + try: + return ovfcheck(x< Author: pedronis Date: Wed Mar 29 00:14:11 2006 New Revision: 25093 Modified: pypy/dist/pypy/translator/backendopt/stat.py Log: flag to ignore stack checks (at least just after rtyping) Modified: pypy/dist/pypy/translator/backendopt/stat.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/stat.py (original) +++ pypy/dist/pypy/translator/backendopt/stat.py Wed Mar 29 00:14:11 2006 @@ -1,7 +1,7 @@ from pypy.translator.simplify import get_graph import md5 -def get_statistics(graph, translator, save_per_graph_details=None): +def get_statistics(graph, translator, save_per_graph_details=None, ignore_stack_checks=False): seen_graphs = {} stack = [graph] num_graphs = 0 @@ -21,6 +21,9 @@ for op in block.operations: if op.opname == "direct_call": called_graph = get_graph(op.args[0], translator) + if called_graph is not None and ignore_stack_checks: + if called_graph.name.startswith('ll_stack_check'): + continue if called_graph is not None: stack.append(called_graph) elif op.opname == "indirect_call": @@ -47,8 +50,9 @@ f.close() return num_graphs, num_blocks, num_ops -def print_statistics(graph, translator, save_per_graph_details=None): - num_graphs, num_blocks, num_ops = get_statistics(graph, translator, save_per_graph_details) +def print_statistics(graph, translator, save_per_graph_details=None, ignore_stack_checks=False): + num_graphs, num_blocks, num_ops = get_statistics(graph, translator, save_per_graph_details, + ignore_stack_checks=ignore_stack_checks) print ("Statistics:\nnumber of graphs %s\n" "number of blocks %s\n" "number of operations %s\n") % (num_graphs, num_blocks, num_ops) From tismer at codespeak.net Wed Mar 29 09:55:31 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 29 Mar 2006 09:55:31 +0200 (CEST) Subject: [pypy-svn] r25098 - pypy/dist/pypy/translator/c/test Message-ID: <20060329075531.AAA161009B@code0.codespeak.net> Author: tismer Date: Wed Mar 29 09:55:28 2006 New Revision: 25098 Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py Log: wrapping with conditional caching of the wrapper. Problem: to put that into rclass.py, I have the problem that I cannot use a python function that checks whether to call the one or the other helper. Do I need hlinvoke for that??? Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Wed Mar 29 09:55:28 2006 @@ -82,34 +82,63 @@ def create_pywrapper(thing): RaiseNameError +def fetch_pywrapper(thing): + RaiseNameError + +def wrap_obj(thing): + res = fetch_pywrapper(thing) + if res is None: + return create_pywrapper(thing) + def unwrap_obj(pyobj, typ): RaiseNameError -def call_destructor(thing): - ll_call_destructor(thing) +def call_destructor(thing, savedrepr): + ll_call_destructor(thing, savedrepr) -def ll_call_destructor(thang): +def ll_call_destructor(thang, savedtrpr): return 42 # really not relevant """ creating a wrapper object with its destructor. Note that we need annotate_helper_fn, because the destructor is never explicitly called. +Note also the "hand specialization" which passes the repr through! +This was only possible with Samuele's hints. """ -def rtype_wrap_object(hop): +def rtype_wrap_object_create(hop): v_any, = hop.inputargs(*hop.args_r) f = call_destructor hop.genop('gc_protect', [v_any]) - ARGTYPE = hop.args_r[0].lowleveltype - FUNCTYPE = lltype.FuncType([ARGTYPE], lltype.Void) - fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARGTYPE]) + repr = hop.args_r[0] + ARGTYPE = repr.lowleveltype + reprPBC = hop.rtyper.annotator.bookkeeper.immutablevalue(repr) + fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARGTYPE, reprPBC]) + FUNCTYPE = lltype.FuncType([ARGTYPE, lltype.Void], lltype.Void) c_dtor = hop.inputconst(lltype.Ptr(FUNCTYPE), fp_dtor) - return hop.llops.gencapicall('PyCObject_FromVoidPtr', [v_any, c_dtor], - resulttype=hop.r_result) + res = hop.llops.gencapicall('PyCObject_FromVoidPtr', [v_any, c_dtor], + resulttype=hop.r_result) + if '_wrapper_' in repr.allinstancefields: + repr.setfield(v_any, '_wrapper_', res, hop.llops) + hop.genop('gc_unprotect', [res]) # yes a weak ref + return res + +def rtype_wrap_object_fetch(hop): + v_any, = hop.inputargs(*hop.args_r) + repr = hop.args_r[0] + if '_wrapper_' in repr.allinstancefields: + return repr.getfield(v_any, '_wrapper_', hop.llops) + else: + null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) + return null def rtype_destruct_object(hop): - v_any, = hop.inputargs(hop.args_r[0]) + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value + if '_wrapper_' in repr.allinstancefields: + null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) + repr.setfield(v_any, '_wrapper_', null, hop.llops) hop.genop('gc_unprotect', [v_any]) def rtype_unwrap_object(hop): @@ -139,7 +168,11 @@ extregistry.register_value(create_pywrapper, compute_result_annotation=annmodel.SomeObject(), - specialize_call=rtype_wrap_object) + specialize_call=rtype_wrap_object_create) + + extregistry.register_value(fetch_pywrapper, + compute_result_annotation=annmodel.SomeObject(), + specialize_call=rtype_wrap_object_fetch) extregistry.register_value(ll_call_destructor, compute_result_annotation=lambda *args:None, @@ -212,14 +245,8 @@ # we have more helper functions here than needed. # this was to make the debugging easier. -def call_create_pywrapper(inst): - return create_pywrapper(inst) - # this could work, but we need to loose ref. - # also: how to generically know if we have the attribute? - if inst._wrapper: - return inst._wrapper - inst._wrapper = create_pywrapper(inst) - return inst._wrapper +def call_wrap_obj(inst): + return wrap_obj(inst) def call_unwrap_obj(pyobj, klass): return unwrap_obj(pyobj, klass) @@ -229,7 +256,7 @@ if a == -42: return democlass_helper_sub(a-1, b) inst = DemoClass(a, b) - pyobj = call_create_pywrapper(inst) + pyobj = call_wrap_obj(inst) obj = call_unwrap_obj(pyobj, DemoClass) ret = obj.demo() return ret @@ -247,13 +274,13 @@ # creating an object, wrapping, unwrapping, call function, check whether __del__ is called def test_wrap_call_dtor(): - f = getcompiled(democlass_helper, use_boehm=not True) + f = getcompiled(democlass_helper, use_boehm=not True, exports=[DemoClass]) ret = f(2, 3) if P: print ret assert ret[0] == 1 # exposing and using classes from a generasted extension module -def test_expose_classes(): +def xtest_expose_classes(): m = get_compiled_module(democlass_helper2, use_boehm=not True, exports=[ DemoClass, DemoSubclass, DemoNotAnnotated]) obj = m.DemoClass(2, 3) From antocuni at codespeak.net Wed Mar 29 10:33:38 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Mar 2006 10:33:38 +0200 (CEST) Subject: [pypy-svn] r25099 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20060329083338.6FE0F100A3@code0.codespeak.net> Author: antocuni Date: Wed Mar 29 10:33:36 2006 New Revision: 25099 Modified: pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/compile.py Log: Some refactoring around opcodes.py and function.py Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Wed Mar 29 10:33:36 2006 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem.lltype import Void from pypy.translator.cli.option import getoption from pypy.translator.cli import cts -from pypy.translator.cli.opcodes import opcodes, DoNothing, PushArgs, PushArg +from pypy.translator.cli.opcodes import opcodes, MicroInstruction, PushAllArgs, Literal from pypy.tool.ansi_print import ansi_log import py @@ -57,11 +57,11 @@ if self._is_return_block(block): return_var = block.inputargs[0] if return_var.concretetype is not Void: - self._push(return_var) + self.load(return_var) self.ilasm.opcode('ret') elif self._is_raise_block(block): exc = block.inputargs[1] - self._push(exc) + self.load(exc) self.ilasm.opcode('throw') if handle_exc: @@ -87,7 +87,7 @@ # the exception value is on the stack, use it as the 2nd target arg assert len(link.args) == 2 assert len(target.inputargs) == 2 - self._store(link.target.inputargs[1]) + self.store(link.target.inputargs[1]) else: # pop the unused exception value self.ilasm.opcode('pop') @@ -107,7 +107,7 @@ else: assert type(link.exitcase is bool) assert block.exitswitch is not None - self._push(block.exitswitch) + self.load(block.exitswitch) self.ilasm.branch_if(link.exitcase, target_label) @@ -125,8 +125,8 @@ target = link.target for to_load, to_store in zip(link.args, target.inputargs): if to_load.concretetype is not Void: - self._push(to_load) - self._store(to_store) + self.load(to_load) + self.store(to_store) def _set_locals(self): @@ -182,10 +182,7 @@ opname = op.opname cli_opcode = opcodes.get(opname, None) - if cli_opcode is DoNothing: # simply rename the variable - self._push(op.args[0]) - self._store(op.result) - elif cli_opcode is not None: + if cli_opcode is not None: self._render_cli_opcode(cli_opcode, op) elif opname == 'direct_call': self._call(op) @@ -198,20 +195,18 @@ def _render_cli_opcode(self, cli_opcode, op): if type(cli_opcode) is str: - instructions = [PushArgs, cli_opcode] + instructions = [PushAllArgs(), cli_opcode] else: instructions = cli_opcode for instr in instructions: - if instr is PushArgs: - for arg in op.args: - self._push(arg) - elif isinstance(instr, PushArg): - self._push(op.args[instr.arg]) - else: - self.ilasm.opcode(instr) + if type(instr) is str: + instr = Literal(instr) + + assert isinstance(instr, MicroInstruction) + instr.render(self, op) - self._store(op.result) + self.store(op.result) def _call(self, op): @@ -219,12 +214,15 @@ # push parameters for func_arg in op.args[1:]: - self._push(func_arg) + self.load(func_arg) self.ilasm.call(func_name) - self._store(op.result) + self.store(op.result) + + def emit(self, instr, *args): + self.ilasm.opcode(instr, *args) - def _push(self, v): + def load(self, v): if isinstance(v, flowmodel.Variable): if v.name in self.argset: self.ilasm.opcode('ldarg', repr(v.name)) @@ -237,7 +235,7 @@ else: assert False - def _store(self, v): + def store(self, v): if isinstance(v, flowmodel.Variable): if v.concretetype is not Void: self.ilasm.opcode('stloc', repr(v.name)) Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Wed Mar 29 10:33:36 2006 @@ -1,15 +1,36 @@ -DoNothing = object() -PushArgs = object() +class MicroInstruction(object): + def render(self, generator, op): + pass -# come useful instruction patterns -Not = ['ldc.i4.0', 'ceq'] -class PushArg(object): - def __init__(self, arg): - self.arg = arg +class Literal(MicroInstruction): + def __init__(self, instr): + self.instr = instr + + def render(self, generator, op): + generator.emit(self.instr) + + +class PushArg(MicroInstruction): + def __init__(self, n): + self.n = n + + def render(self, generator, op): + generator.load(op.args[self.n]) + + +class PushAllArgs(MicroInstruction): + def render(self, generator, op): + for arg in op.args: + generator.load(arg) + + +# some useful instruction patterns +Not = ['ldc.i4.0', 'ceq'] +DoNothing = [PushAllArgs()] def _not(op): - return [PushArgs, op]+Not + return [PushAllArgs(), op]+Not opcodes = { @@ -33,7 +54,7 @@ 'int_is_true': DoNothing, 'int_neg': 'neg', - 'int_neg_ovf': ['ldc.i4.0', PushArgs, 'sub.ovf'], + 'int_neg_ovf': ['ldc.i4.0', PushAllArgs(), 'sub.ovf'], 'int_abs': None, # TODO 'int_abs_ovf': None, # TODO 'int_invert': 'not', @@ -69,7 +90,11 @@ 'int_ge_ovf': _not('clt'), 'int_and_ovf': 'and', 'int_or_ovf': 'or', + + # are they the same? + 'int_lshift_ovf': [PushArg(0), 'conv.i8', PushArg(1), 'shl', 'conv.ovf.i4'], 'int_lshift_ovf_val': [PushArg(0), 'conv.i8', PushArg(1), 'shl', 'conv.ovf.i4'], + 'int_rshift_ovf': 'shr', # these can't overflow! 'int_xor_ovf': 'xor', 'int_floordiv_ovf_zer': None, # what's the meaning? @@ -99,7 +124,7 @@ 'uint_rshift': 'shr.un', 'uint_xor': 'xor', - 'float_is_true': [PushArgs, 'ldc.r8 0', 'ceq']+Not, + 'float_is_true': [PushAllArgs(), 'ldc.r8 0', 'ceq']+Not, 'float_neg': 'neg', 'float_abs': None, # TODO @@ -119,7 +144,7 @@ 'float_floor': None, # TODO 'float_fmod': None, # TODO - 'llong_is_true': [PushArgs, 'ldc.i8 0', 'ceq']+Not, + 'llong_is_true': [PushAllArgs(), 'ldc.i8 0', 'ceq']+Not, 'llong_neg': 'neg', 'llong_abs': None, # TODO 'llong_invert': 'not', @@ -138,7 +163,7 @@ 'llong_gt': 'cgt', 'llong_ge': _not('clt'), - 'ullong_is_true': [PushArgs, 'ldc.i8 0', 'ceq']+Not, + 'ullong_is_true': [PushAllArgs(), 'ldc.i8 0', 'ceq']+Not, 'ullong_neg': None, 'ullong_abs': None, # TODO 'ullong_invert': 'not', @@ -161,9 +186,9 @@ # to 1: we can't simply DoNothing, because the CLI stack could # contains a truth value not equal to 1, so we should use the !=0 # trick. - 'cast_bool_to_int': [PushArgs, 'ldc.i4.0', 'ceq']+Not, - 'cast_bool_to_uint': [PushArgs, 'ldc.i4.0', 'ceq']+Not, - 'cast_bool_to_float': [PushArgs, 'ldc.i4 0', 'ceq']+Not+['conv.r8'], + 'cast_bool_to_int': [PushAllArgs(), 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_uint': [PushAllArgs(), 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_float': [PushAllArgs(), 'ldc.i4 0', 'ceq']+Not+['conv.r8'], 'cast_char_to_int': None, 'cast_unichar_to_int': None, 'cast_int_to_char': None, Modified: pypy/dist/pypy/translator/cli/test/compile.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/compile.py (original) +++ pypy/dist/pypy/translator/cli/test/compile.py Wed Mar 29 10:33:36 2006 @@ -23,12 +23,14 @@ else: print 'OK' - -def foo(x, y, z): - pass +def foo(x): + return x+1 def bar(x, y): - foo(x+y, x-y, x*y) + if x > y: + return x+y+foo(2) + else: + return x-y f = compile_function(bar, [int, int]) From ericvrp at codespeak.net Wed Mar 29 14:32:40 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 29 Mar 2006 14:32:40 +0200 (CEST) Subject: [pypy-svn] r25102 - in pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi: . lib lib/Analysis lib/Bytecode lib/ExecutionEngine lib/System lib/Transforms lib/VMCore Message-ID: <20060329123240.57BC71009D@code0.codespeak.net> Author: ericvrp Date: Wed Mar 29 14:32:33 2006 New Revision: 25102 Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.py - copied, changed from r25098, pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.sh pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/Verifier.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/_Analysis.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Reader.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Writer.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/_Bytecode.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/ExecutionEngine.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValue.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValueHolder.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/_ExecutionEngine.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/Path.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/_System.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/IPO.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Instrumentation.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Scalar.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/_Transforms.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/AbstractTypeUser.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Annotation.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Argument.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/BasicBlock.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/CallGraphSCCPass.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constant.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constants.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/DerivedTypes.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Function.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalValue.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalVariable.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/InstrTypes.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instruction.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions1.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions2.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/IntrinsicInst.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Intrinsics.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Linker.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Module.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/ModuleProvider.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Pass.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassAnalysisSupport.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassManager.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassSupport.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/SymbolTable.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Type.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Use.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/User.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Value.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/_VMCore.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/inst_init.cpp (contents, props changed) pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.cpp pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.h Removed: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/create_pyllvm.sh pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.cpp pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/llvmcapi.h Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py Log: For llvmcapi and pyllvm use .py instead of .sh file and added files with llvm directory structure Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/Verifier.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/Verifier.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/_Analysis.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Analysis/_Analysis.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Reader.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Reader.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Writer.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/Writer.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/_Bytecode.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Bytecode/_Bytecode.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/ExecutionEngine.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/ExecutionEngine.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValue.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValue.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValueHolder.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/GenericValueHolder.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/_ExecutionEngine.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/ExecutionEngine/_ExecutionEngine.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/Path.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/Path.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/_System.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/System/_System.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/IPO.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/IPO.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Instrumentation.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Instrumentation.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Scalar.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/Scalar.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/_Transforms.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/Transforms/_Transforms.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/AbstractTypeUser.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/AbstractTypeUser.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Annotation.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Annotation.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Argument.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Argument.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/BasicBlock.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/BasicBlock.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/CallGraphSCCPass.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/CallGraphSCCPass.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constant.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constant.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constants.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Constants.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/DerivedTypes.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/DerivedTypes.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Function.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Function.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalValue.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalValue.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalVariable.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/GlobalVariable.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/InstrTypes.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/InstrTypes.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instruction.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instruction.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions1.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions1.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions2.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Instructions2.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/IntrinsicInst.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/IntrinsicInst.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Intrinsics.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Intrinsics.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Linker.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Linker.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Module.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Module.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/ModuleProvider.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/ModuleProvider.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Pass.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Pass.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassAnalysisSupport.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassAnalysisSupport.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassManager.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassManager.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassSupport.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/PassSupport.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/SymbolTable.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/SymbolTable.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Type.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Type.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Use.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Use.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/User.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/User.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Value.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/Value.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/_VMCore.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/_VMCore.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/inst_init.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/VMCore/inst_init.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1 @@ +// TODO: write C++ -> C wrapper Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.cpp Wed Mar 29 14:32:33 2006 @@ -0,0 +1,29 @@ +#include "llvmcapi.h" + +// llvm includes +#include "llvm/Type.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/Assembly/Parser.h" +#include "llvm/Bytecode/Reader.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/DerivedTypes.h" + +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + + +// c++ includes +#include +#include + + +int testme1(int n) { + return n * n; +} + +float testme2(float f) { + return f * f; +} Added: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/lib/llvmcapi.h Wed Mar 29 14:32:33 2006 @@ -0,0 +1,16 @@ + +#ifndef LLVMCAPI_H +#define LLVMCAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +int testme1(int n); +float testme2(float f); + +#ifdef __cplusplus +}; +#endif + +#endif Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/pyllvm.py Wed Mar 29 14:32:33 2006 @@ -5,13 +5,13 @@ def testme1(n): - # llvmcapi.h 9 + # lib/llvmcapi.h 9 return testme1._api_(n) testme1 = cdecl(c_int, 'llvmcapi', [c_int]) (testme1) def testme2(f): - # llvmcapi.h 10 + # lib/llvmcapi.h 10 return testme2._api_(f) testme2 = cdecl(c_float, 'llvmcapi', [c_float]) (testme2) Modified: pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/llvmcapi/setup.py Wed Mar 29 14:32:33 2006 @@ -7,7 +7,7 @@ libs = popen('llvm-config --libs all').readline().split() opts = dict(name='llvmcapi', - sources=['llvmcapi.cpp'], + sources=['lib/llvmcapi.cpp'], libraries=[], include_dirs =[f[2:] for f in cxxflags if f.startswith('-I')], library_dirs =[f[2:] for f in ldflags if f.startswith('-L')], From antocuni at codespeak.net Wed Mar 29 15:53:50 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Mar 2006 15:53:50 +0200 (CEST) Subject: [pypy-svn] r25107 - pypy/dist/pypy/translator/cli Message-ID: <20060329135350.E661A100A6@code0.codespeak.net> Author: antocuni Date: Wed Mar 29 15:53:43 2006 New Revision: 25107 Added: pypy/dist/pypy/translator/cli/metavm.py (contents, props changed) Modified: pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/opcodes.py Log: More opcodes refactoring Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Wed Mar 29 15:53:43 2006 @@ -2,7 +2,8 @@ from pypy.rpython.lltypesystem.lltype import Void from pypy.translator.cli.option import getoption from pypy.translator.cli import cts -from pypy.translator.cli.opcodes import opcodes, MicroInstruction, PushAllArgs, Literal +from pypy.translator.cli.opcodes import opcodes +from pypy.translator.cli.metavm import InstructionList, Generator from pypy.tool.ansi_print import ansi_log import py @@ -18,7 +19,7 @@ pass -class Function(Node): +class Function(Node, Generator): def __init__(self, graph, is_entrypoint = False): self.graph = graph self.is_entrypoint = is_entrypoint @@ -179,13 +180,10 @@ return 'block%s' % self.blocknum[block] def _render_op(self, op): - opname = op.opname - - cli_opcode = opcodes.get(opname, None) - if cli_opcode is not None: - self._render_cli_opcode(cli_opcode, op) - elif opname == 'direct_call': - self._call(op) + instr_list = opcodes.get(op.opname, None) + if instr_list is not None: + assert isinstance(instr_list, InstructionList) + instr_list.render(self, op) else: if getoption('nostop'): log.WARNING('Unknown opcode: %s ' % op) @@ -193,35 +191,17 @@ else: assert False, 'Unknown opcode: %s ' % op - def _render_cli_opcode(self, cli_opcode, op): - if type(cli_opcode) is str: - instructions = [PushAllArgs(), cli_opcode] - else: - instructions = cli_opcode - - for instr in instructions: - if type(instr) is str: - instr = Literal(instr) - - assert isinstance(instr, MicroInstruction) - instr.render(self, op) - - self.store(op.result) - + # following methods belongs to the Generator interface - def _call(self, op): - func_name = cts.graph_to_signature(op.args[0].value.graph) - - # push parameters - for func_arg in op.args[1:]: - self.load(func_arg) - - self.ilasm.call(func_name) - self.store(op.result) + def function_name(self, graph): + return cts.graph_to_signature(graph) def emit(self, instr, *args): self.ilasm.opcode(instr, *args) + def call(self, func_name): + self.ilasm.call(func_name) + def load(self, v): if isinstance(v, flowmodel.Variable): if v.name in self.argset: Added: pypy/dist/pypy/translator/cli/metavm.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/metavm.py Wed Mar 29 15:53:43 2006 @@ -0,0 +1,63 @@ +class Generator(object): + def function_name(self, graph): + pass + + def emit(self, instr, *args): + pass + + def call(self, func_name): + pass + + def load(self, v): + pass + + def store(self, v): + pass + + +class InstructionList(list): + def render(self, generator, op): + for instr in self: + if isinstance(instr, MicroInstruction): + instr.render(generator, op) + else: + generator.emit(instr) + + +class MicroInstruction(object): + def render(self, generator, op): + pass + + +class PushArg(MicroInstruction): + def __init__(self, n): + self.n = n + + def render(self, generator, op): + generator.load(op.args[self.n]) + + +class _PushAllArgs(MicroInstruction): + def render(self, generator, op): + for arg in op.args: + generator.load(arg) + + +class _StoreResult(MicroInstruction): + def render(self, generator, op): + generator.store(op.result) + + +class _Call(MicroInstruction): + def render(self, generator, op): + func_name = generator.function_name(op.args[0].value.graph) + + # push parameters + for func_arg in op.args[1:]: + generator.load(func_arg) + + generator.call(func_name) + +PushAllArgs = _PushAllArgs() +StoreResult = _StoreResult() +Call = _Call() Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Wed Mar 29 15:53:43 2006 @@ -1,42 +1,17 @@ -class MicroInstruction(object): - def render(self, generator, op): - pass - - -class Literal(MicroInstruction): - def __init__(self, instr): - self.instr = instr - - def render(self, generator, op): - generator.emit(self.instr) - - -class PushArg(MicroInstruction): - def __init__(self, n): - self.n = n - - def render(self, generator, op): - generator.load(op.args[self.n]) - - -class PushAllArgs(MicroInstruction): - def render(self, generator, op): - for arg in op.args: - generator.load(arg) - +from pypy.translator.cli.metavm import PushArg, PushAllArgs, StoreResult, Call, InstructionList # some useful instruction patterns Not = ['ldc.i4.0', 'ceq'] -DoNothing = [PushAllArgs()] +DoNothing = [PushAllArgs] def _not(op): - return [PushAllArgs(), op]+Not + return [PushAllArgs, op]+Not opcodes = { 'same_as': DoNothing, # TODO: does same_as really do nothing else than renaming? - 'direct_call': None, # for now it's a special case - 'indirect_call': None, # when it's generated? + 'direct_call': [Call], + 'indirect_call': None, # when is it generated? # __________ numeric operations __________ @@ -54,7 +29,7 @@ 'int_is_true': DoNothing, 'int_neg': 'neg', - 'int_neg_ovf': ['ldc.i4.0', PushAllArgs(), 'sub.ovf'], + 'int_neg_ovf': ['ldc.i4.0', PushAllArgs, 'sub.ovf'], 'int_abs': None, # TODO 'int_abs_ovf': None, # TODO 'int_invert': 'not', @@ -124,7 +99,7 @@ 'uint_rshift': 'shr.un', 'uint_xor': 'xor', - 'float_is_true': [PushAllArgs(), 'ldc.r8 0', 'ceq']+Not, + 'float_is_true': [PushAllArgs, 'ldc.r8 0', 'ceq']+Not, 'float_neg': 'neg', 'float_abs': None, # TODO @@ -144,7 +119,7 @@ 'float_floor': None, # TODO 'float_fmod': None, # TODO - 'llong_is_true': [PushAllArgs(), 'ldc.i8 0', 'ceq']+Not, + 'llong_is_true': [PushAllArgs, 'ldc.i8 0', 'ceq']+Not, 'llong_neg': 'neg', 'llong_abs': None, # TODO 'llong_invert': 'not', @@ -163,7 +138,7 @@ 'llong_gt': 'cgt', 'llong_ge': _not('clt'), - 'ullong_is_true': [PushAllArgs(), 'ldc.i8 0', 'ceq']+Not, + 'ullong_is_true': [PushAllArgs, 'ldc.i8 0', 'ceq']+Not, 'ullong_neg': None, 'ullong_abs': None, # TODO 'ullong_invert': 'not', @@ -186,9 +161,9 @@ # to 1: we can't simply DoNothing, because the CLI stack could # contains a truth value not equal to 1, so we should use the !=0 # trick. - 'cast_bool_to_int': [PushAllArgs(), 'ldc.i4.0', 'ceq']+Not, - 'cast_bool_to_uint': [PushAllArgs(), 'ldc.i4.0', 'ceq']+Not, - 'cast_bool_to_float': [PushAllArgs(), 'ldc.i4 0', 'ceq']+Not+['conv.r8'], + 'cast_bool_to_int': [PushAllArgs, 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_uint': [PushAllArgs, 'ldc.i4.0', 'ceq']+Not, + 'cast_bool_to_float': [PushAllArgs, 'ldc.i4 0', 'ceq']+Not+['conv.r8'], 'cast_char_to_int': None, 'cast_unichar_to_int': None, 'cast_int_to_char': None, @@ -201,3 +176,12 @@ 'cast_float_to_uint': 'conv.i4', 'truncate_longlong_to_int': 'conv.i4', } + +for key, value in opcodes.iteritems(): + if type(value) is str: + value = InstructionList([PushAllArgs, value, StoreResult]) + elif value is not None: + value = InstructionList(value + [StoreResult]) + + opcodes[key] = value + From auc at codespeak.net Wed Mar 29 18:07:20 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 29 Mar 2006 18:07:20 +0200 (CEST) Subject: [pypy-svn] r25117 - in pypy/dist/pypy/objspace: . test Message-ID: <20060329160720.4FF2D100AB@code0.codespeak.net> Author: auc Date: Wed Mar 29 18:07:18 2006 New Revision: 25117 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: multimethodification of unify Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Wed Mar 29 18:07:18 2006 @@ -2,8 +2,14 @@ from pypy.interpreter import gateway, baseobjspace, argument from pypy.interpreter.error import OperationError from pypy.rpython.objectmodel import we_are_translated + +# wrapped types, mm stuff from pypy.objspace.std.listobject import W_ListObject, W_TupleObject from pypy.objspace.std.dictobject import W_DictObject +from pypy.objspace.std.objectobject import W_ObjectObject +from pypy.objspace.std.model import StdObjSpaceMultiMethod + +#-- THE BUILTINS ---------------------------------------------------------------------- USE_COROUTINES = True HAVE_GREENLETS = True @@ -160,6 +166,7 @@ class W_Var(baseobjspace.W_Root, object): def __init__(w_self): + w_self.typedef = 'Variable' w_self.w_bound_to = w_self w_self.w_needed = False @@ -178,7 +185,7 @@ while 1: if not isinstance(w_self, W_Var): return w_self - print " :wait", w_self + #print " :wait", w_self if space.is_true(is_free(space, w_self)): if not have_uthreads(): raise OperationError(space.w_RuntimeError, @@ -443,66 +450,50 @@ #-- UNIFY ------------------------- def unify(space, w_x, w_y): - print " :unify", w_x, w_y - check_and_memoize_pair(space, w_x, w_y) - if not isinstance(w_x, W_Var): - if not isinstance(w_y, W_Var): - # x, y not vars - return _unify_values(space, w_x, w_y) - # x not var, reverse args. order - return unify(space, w_y, w_x) - elif not isinstance(w_y, W_Var): - # x var, y value - if space.is_true(is_bound(space, w_x)): - return unify(space, deref(space, w_x), w_y) - return bind(space, w_x, w_y) - # x, y are vars - elif space.is_true(is_bound(space, w_x)): + print ":unify ", w_x, w_y + return space.unify(w_x, w_y) +app_unify = gateway.interp2app(unify) + +def unify__Root_Root(space, w_x, w_y): + if not space.eq_w(w_x, w_y): + try: + w_d1 = w_x.getdict() + w_d2 = w_y.getdict() + return space.unify(w_d1, w_d2) + except: + fail(space, w_x, w_y) + return space.w_None + +def unify__Var_Var(space, w_x, w_y): + print " :unify of two vars" + if space.is_true(is_bound(space, w_x)): if space.is_true(is_bound(space, w_y)): - return _unify_values(space, - deref(space, w_x), - deref(space, w_y)) + return space.unify(deref(space, w_x), + deref(space, w_y)) return bind(space, w_y, w_x) - # aliasing x & y ? + # binding or aliasing x & y else: - return bind(space, w_x, w_y) # aliasing - reset_memo() -app_unify = gateway.interp2app(unify) - + return bind(space, w_x, w_y) -def _unify_values(space, w_v1, w_v2): - print " :unify values", w_v1, w_v2 - # unify object of the same type ... FIXME - if not space.is_w(space.type(w_v1), - space.type(w_v2)): - fail(space, w_v1, w_v2) - # ... elements of a list/tuple ... - if (isinstance(w_v1, W_ListObject) and \ - isinstance(w_v2, W_ListObject)) or \ - (isinstance(w_v1, W_TupleObject) and \ - isinstance(w_v1, W_TupleObject)): - return _unify_iterables(space, w_v1, w_v2) - elif isinstance(w_v1, W_DictObject) and \ - isinstance(w_v1, W_DictObject): - return _unify_mappings(space, w_v1, w_v2) - # ... token equality - if not space.eq_w(w_v1, w_v2): - return _unify_instances(space, w_v1, w_v2) - #fail(space, w_v1, w_v2) - return space.w_None +def unify__Var_Root(space, w_x, w_y): + print " :unify of a var and a value" + if space.is_true(is_bound(space, w_x)): + return space.unify(deref(space, w_x), w_y) + return bind(space, w_x, w_y) + +def unify__Root_Var(space, w_x, w_y): + return space.unify(w_y, w_x) -def _unify_instances(space, w_i1, w_i2): - print " :unify instances" - return _unify_mappings(space, - w_i1.getdict(), - w_i2.getdict()) +def unify__Tuple_Tuple(space, w_x, w_y): + return _unify_iterables(space, w_x, w_y) +def unify__List_List(space, w_x, w_y): + return _unify_iterables(space, w_x, w_y) + def _unify_iterables(space, w_i1, w_i2): - print " :unify iterables", w_i1, w_i2 - # assert lengths + print " :unify iterables", w_i1, w_i2 if len(w_i1.wrappeditems) != len(w_i2.wrappeditems): fail(space, w_i1, w_i2) - # co-iterate and unify elts idx, top = (-1, space.int_w(space.len(w_i1))-1) while idx < top: idx += 1 @@ -512,44 +503,31 @@ continue unify(space, w_xi, w_yi) -def _unify_mappings(space, w_m1, w_m2): - print " :unify mappings", w_m1, w_m2 -## if len(w_m1.wrappeditems) != len(w_m2.wrappeditems): -## fail(space, w_i1, w_i2) +def unify__Dict_Dict(space, w_m1, w_m2): + print " :unify mappings", w_m1, w_m2 for w_xk in w_m1.content.keys(): w_xi = space.getitem(w_m1, w_xk) w_yi = space.getitem(w_m2, w_xk) if space.is_true(space.is_nb_(w_xi, w_yi)): continue - unify(space, w_xi, w_yi) - - - -# multimethod version of unify -## def unify__W_Var_W_Var(space, w_v1, w_v2): -## return bind(space, w_v1, w_v2) - -## def unify__W_Var_W_ObjectObject(space, w_var, w_obj): -## return bind(space, w_v1, w_obj) - -## def unify_W_ObjectObject_W_Var(space, w_obj, w_var): -## return unify__W_Var_W_ObjectObject(space, w_var, w_obj) + space.unify(w_xi, w_yi) -## def unify__W_ObjectObject_W_ObjectObject(space, w_obj1, w_obj2): -## if not space.eq(w_obj1, w_obj2): -## fail(space, w_obj1, w_obj2) -## return space.w_None -## def unify__W_ListObject_W_ListObject(space, w_list1, w_list2): -## if len(w_list1) != len(w_list2): # .wrappeditems ? -## fail(space, w_list1, w_list2) -## for e1, e2 in zip(w_list1, w_list2): # .wrappeditems ? -## space.wrap(unify(space, e1, e2)) # ... ? - -# questions : how to make this available to applevel ? +W_Root = baseobjspace.W_Root + +unify_mm = StdObjSpaceMultiMethod('unify', 2) +unify_mm.register(unify__Root_Root, W_Root, W_Root) +unify_mm.register(unify__Var_Var, W_Var, W_Var) +unify_mm.register(unify__Var_Root, W_Var, W_Root) +unify_mm.register(unify__Root_Var, W_Root, W_Var) +unify_mm.register(unify__Tuple_Tuple, W_TupleObject, W_TupleObject) +unify_mm.register(unify__List_List, W_ListObject, W_ListObject) +unify_mm.register(unify__Dict_Dict, W_DictObject, W_DictObject) +all_mms = {} +all_mms['unify'] = unify_mm -# __________________________________________________________________________ +#-- SPACE HELPERS ------------------------------------- nb_forcing_args = {} @@ -558,6 +536,7 @@ 'setattr': 2, # instead of 3 'setitem': 2, # instead of 3 'get': 2, # instead of 3 + 'unify': 2, # ---- irregular operations ---- 'wrap': 0, 'str_w': 1, @@ -626,7 +605,6 @@ return parentfn(wait(space, w_obj1), wait(space, w_obj2)) return ne - def proxymaker(space, opname, parentfn): if opname == "eq": return eqproxy(space, parentfn) @@ -661,31 +639,11 @@ +#-- THE SPACE --------------------------------------- -from pypy.objspace.std.model import StdObjSpaceMultiMethod -from pypy.objspace.std.intobject import W_IntObject -from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std import stdtypedef from pypy.tool.sourcetools import func_with_new_name -def foo__Int_Int(space, w_a, w_b): - print "i'm foo int int" - -def foo__Int_Float(space, w_a, w_b): - print "i'm foo int float" - -def foo__Float_Int(space, w_a, w_b): - space.foo(w_b, w_a) - - -foo_mm = StdObjSpaceMultiMethod('foo', 2) -foo_mm.register(foo__Int_Int, W_IntObject, W_IntObject) -foo_mm.register(foo__Int_Float, W_IntObject, W_FloatObject) -foo_mm.register(foo__Float_Int, W_FloatObject, W_IntObject) - -def my_foo(space, w_1, w_2): - space.foo(w_1, w_2) -app_foo = gateway.interp2app(my_foo) def Space(*args, **kwds): # for now, always make up a wrapped StdObjSpace @@ -693,19 +651,22 @@ space = std.Space(*args, **kwds) # multimethods hack - name = 'foo' - exprargs, expr, miniglobals, fallback = ( - foo_mm.install_not_sliced(space.model.typeorder, baked_perform_call=False)) - func = stdtypedef.make_perform_trampoline('__foo_mm_'+name, - exprargs, expr, miniglobals, - foo_mm) - # e.g. add(space, w_x, w_y) - def make_boundmethod(func=func): - def boundmethod(*args): - return func(space, *args) - return func_with_new_name(boundmethod, 'boundmethod_'+name) - boundmethod = make_boundmethod() - setattr(space, name, boundmethod) # store into 'space' instance + #space.model.typeorder[W_Var] = [(baseobjspace.W_Root, None)] + space.model.typeorder[W_Var] = [(W_Var, None), (baseobjspace.W_Root, None)] + for name in all_mms.keys(): + exprargs, expr, miniglobals, fallback = ( + all_mms[name].install_not_sliced(space.model.typeorder, baked_perform_call=False)) + func = stdtypedef.make_perform_trampoline('__mm_' + name, + exprargs, expr, miniglobals, + all_mms[name]) + # e.g. add(space, w_x, w_y) + def make_boundmethod(func=func): + def boundmethod(*args): + return func(space, *args) + return func_with_new_name(boundmethod, 'boundmethod_'+name) + boundmethod = make_boundmethod() + print boundmethod + setattr(space, name, boundmethod) # store into 'space' instance # /multimethod hack @@ -728,8 +689,6 @@ space.wrap(app_bind)) space.setitem(space.builtin.w_dict, space.wrap('unify'), space.wrap(app_unify)) - space.setitem(space.builtin.w_dict, space.wrap('foo'), - space.wrap(app_foo)) if USE_COROUTINES: import os def exitfunc(): @@ -751,4 +710,3 @@ space.setitem(space.builtin.w_dict, space.wrap('wait_needed'), space.wrap(app_wait_needed)) return space - Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Wed Mar 29 18:07:18 2006 @@ -195,11 +195,6 @@ unify(f2.b, 'foo') assert f1.b == f2.b == 'foo' - def test_foo(self): - foo(1, 2) - foo(1, 2.0) - foo(2.0, 1) - class AppTest_LogicThreads(object): From auc at codespeak.net Wed Mar 29 19:09:02 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 29 Mar 2006 19:09:02 +0200 (CEST) Subject: [pypy-svn] r25120 - in pypy/dist/pypy/objspace: . test Message-ID: <20060329170902.39A95100B7@code0.codespeak.net> Author: auc Date: Wed Mar 29 19:09:00 2006 New Revision: 25120 Modified: pypy/dist/pypy/objspace/logic.py pypy/dist/pypy/objspace/test/test_logicobjspace.py Log: multimethodification of bind Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Wed Mar 29 19:09:00 2006 @@ -11,6 +11,11 @@ #-- THE BUILTINS ---------------------------------------------------------------------- +# this collects all multimethods to be made part of the Space +all_mms = {} +W_Root = baseobjspace.W_Root + + USE_COROUTINES = True HAVE_GREENLETS = True try: @@ -330,7 +335,8 @@ def fail(space, w_obj1, w_obj2): """raises a specific exception for bind/unify""" - print "can't unify", w_obj1, w_obj2 + #FIXME : really raise some specific exception + print "failed to bind/unify" raise OperationError(space.w_RuntimeError, space.wrap("UnificationFailure")) @@ -347,8 +353,9 @@ def _sleep(space, w_var, w_barrier): wait(space, w_var) bind(space, w_barrier, space.newint(1)) -#app_sleep = gateway.interp2app(sleep) +#FIXME : does not work at all, +# even a pure applevel version ... def wait_two(space, w_1, w_2): """waits until one out of two logic variables becomes bound, then tells which one, @@ -373,28 +380,36 @@ 3. assign value to unbound var """ print " :bind", w_var, w_obj - assert isinstance(w_var, W_Var) - if isinstance(w_obj, W_Var): - if space.is_true(is_bound(space, w_var)): - if space.is_true(is_bound(space, w_obj)): - return unify(space, - deref(space, w_var), - deref(space, w_obj)) - # 2. a (obj unbound, var bound) - return _assign(space, w_obj, deref(space, w_var)) - elif space.is_true(is_bound(space, w_obj)): - # 2. b (var unbound, obj bound) - return _assign(space, w_var, deref(space, w_obj)) - else: # 1. both are unbound - return _alias(space, w_var, w_obj) - else: # 3. w_obj is a value - if space.is_true(is_free(space, w_var)): - return _assign(space, w_var, w_obj) - # should not be reachable as of 27-03-2006 - raise OperationError(space.w_RuntimeError, - space.wrap("Unreachable code in bind")) + space.bind(w_var, w_obj) app_bind = gateway.interp2app(bind) +def bind__Var_Var(space, w_var, w_obj): + if space.is_true(is_bound(space, w_var)): + if space.is_true(is_bound(space, w_obj)): + return unify(space, + deref(space, w_var), + deref(space, w_obj)) + # 2. a (obj unbound, var bound) + return _assign(space, w_obj, deref(space, w_var)) + elif space.is_true(is_bound(space, w_obj)): + # 2. b (var unbound, obj bound) + return _assign(space, w_var, deref(space, w_obj)) + else: # 1. both are unbound + return _alias(space, w_var, w_obj) + + +def bind__Var_Root(space, w_v1, w_v2): + # 3. var and value + if space.is_true(is_free(space, w_v1)): + return _assign(space, w_v1, w_v2) + print "uh !" + fail(space, w_v1, w_v2) + +bind_mm = StdObjSpaceMultiMethod('bind', 2) +bind_mm.register(bind__Var_Root, W_Var, W_Root) +bind_mm.register(bind__Var_Var, W_Var, W_Var) +all_mms['bind'] = bind_mm + def _assign(space, w_var, w_val): print " :assign", w_var, w_val, '[', w_curr = w_var @@ -456,11 +471,11 @@ def unify__Root_Root(space, w_x, w_y): if not space.eq_w(w_x, w_y): - try: - w_d1 = w_x.getdict() - w_d2 = w_y.getdict() + w_d1 = w_x.getdict() + w_d2 = w_y.getdict() + if None not in (w_d1, w_d2): return space.unify(w_d1, w_d2) - except: + else: fail(space, w_x, w_y) return space.w_None @@ -476,7 +491,7 @@ return bind(space, w_x, w_y) def unify__Var_Root(space, w_x, w_y): - print " :unify of a var and a value" + print " :unify var and value" if space.is_true(is_bound(space, w_x)): return space.unify(deref(space, w_x), w_y) return bind(space, w_x, w_y) @@ -513,8 +528,6 @@ space.unify(w_xi, w_yi) -W_Root = baseobjspace.W_Root - unify_mm = StdObjSpaceMultiMethod('unify', 2) unify_mm.register(unify__Root_Root, W_Root, W_Root) unify_mm.register(unify__Var_Var, W_Var, W_Var) @@ -524,7 +537,6 @@ unify_mm.register(unify__List_List, W_ListObject, W_ListObject) unify_mm.register(unify__Dict_Dict, W_DictObject, W_DictObject) -all_mms = {} all_mms['unify'] = unify_mm #-- SPACE HELPERS ------------------------------------- Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_logicobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_logicobjspace.py Wed Mar 29 19:09:00 2006 @@ -194,7 +194,7 @@ assert alias_of(f1.b, f2.b) unify(f2.b, 'foo') assert f1.b == f2.b == 'foo' - + raises(Exception, unify, f1.b, 24) class AppTest_LogicThreads(object): From auc at codespeak.net Wed Mar 29 19:30:09 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 29 Mar 2006 19:30:09 +0200 (CEST) Subject: [pypy-svn] r25123 - pypy/dist/pypy/objspace Message-ID: <20060329173009.74D1A100B6@code0.codespeak.net> Author: auc Date: Wed Mar 29 19:30:08 2006 New Revision: 25123 Modified: pypy/dist/pypy/objspace/logic.py Log: multimethod frenzy Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Wed Mar 29 19:30:08 2006 @@ -186,10 +186,11 @@ return W_Var() app_newvar = gateway.interp2app(newvar) -def wait(space, w_self): +def wait__Root(space, w_self): + return w_self + +def wait__Var(space, w_self): while 1: - if not isinstance(w_self, W_Var): - return w_self #print " :wait", w_self if space.is_true(is_free(space, w_self)): if not have_uthreads(): @@ -220,13 +221,19 @@ space.wrap("blocked on variable, but no uthread that can bind it")) else: return w_self.w_bound_to + +def wait(space, w_obj): + return space.wait(w_obj) app_wait = gateway.interp2app(wait) -def wait_needed(space, w_self): +wait_mm = StdObjSpaceMultiMethod('wait', 1) +wait_mm.register(wait__Var, W_Var) +wait_mm.register(wait__Root, W_Root) +all_mms['wait'] = wait_mm + + +def wait_needed__Var(space, w_self): while 1: - if not isinstance(w_self, W_Var): - raise OperationError(space.w_RuntimeError, - space.wrap("wait_needed operates only on logic variables")) print " :needed", w_self if space.is_true(is_free(space, w_self)): if w_self.w_needed: @@ -254,23 +261,41 @@ else: raise OperationError(space.w_RuntimeError, space.wrap("wait_needed only supported on unbound variables")) + +def wait_needed(space, w_var): + return space.wait_needed(w_var) app_wait_needed = gateway.interp2app(wait_needed) +wait_needed_mm = StdObjSpaceMultiMethod('wait_needed', 1) +wait_needed_mm.register(wait_needed__Var, W_Var) +all_mms['wait_needed'] = wait_needed_mm + #-- PREDICATES -------------------- def is_aliased(space, w_var): # FIXME: this appears to block + assert isinstance(w_var, W_Var) if space.is_true(space.is_nb_(deref(space, w_var), w_var)): return space.newbool(False) return space.newbool(True) app_is_aliased = gateway.interp2app(is_aliased) -def is_free(space, w_var): - if not isinstance(w_var, W_Var): - return space.newbool(False) +def is_free(space, w_obj): + return space.is_free(w_obj) + +def is_free__Root(space, w_obj): + return space.newbool(False) + +def is_free__Var(space, w_var): return space.newbool(isinstance(w_var.w_bound_to, W_Var)) + app_is_free = gateway.interp2app(is_free) +is_free_mm = StdObjSpaceMultiMethod('is_free', 1) +is_free_mm.register(is_free__Root, W_Root) +is_free_mm.register(is_free__Var, W_Var) +all_mms['is_free'] = is_free_mm + def is_bound(space, w_var): return space.newbool(not space.is_true(is_free(space, w_var))) app_is_bound = gateway.interp2app(is_bound) @@ -350,12 +375,13 @@ l = len(a_str) - 1 return a_str[l-3:l] + +#FIXME : does not work at all, +# even a pure applevel version ... def _sleep(space, w_var, w_barrier): wait(space, w_var) bind(space, w_barrier, space.newint(1)) -#FIXME : does not work at all, -# even a pure applevel version ... def wait_two(space, w_1, w_2): """waits until one out of two logic variables becomes bound, then tells which one, @@ -681,10 +707,9 @@ setattr(space, name, boundmethod) # store into 'space' instance # /multimethod hack - is_nb_ = space.is_ # capture the original is_ op (?) - patch_space_in_place(space, 'logic', proxymaker) space.is_nb_ = is_nb_ + space.setitem(space.builtin.w_dict, space.wrap('newvar'), space.wrap(app_newvar)) space.setitem(space.builtin.w_dict, space.wrap('is_free'), @@ -714,6 +739,7 @@ if schedule_state.have_blocked_threads(): os.write(2, "there are still blocked uthreads!") app_exitfunc = gateway.interp2app(exitfunc, unwrap_spec=[]) + space.setitem(space.sys.w_dict, space.wrap("exitfunc"), space.wrap(app_exitfunc)) space.setitem(space.builtin.w_dict, space.wrap('uthread'), space.wrap(app_uthread)) @@ -721,4 +747,5 @@ space.wrap(app_wait)) space.setitem(space.builtin.w_dict, space.wrap('wait_needed'), space.wrap(app_wait_needed)) + patch_space_in_place(space, 'logic', proxymaker) return space From auc at codespeak.net Wed Mar 29 19:57:34 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Wed, 29 Mar 2006 19:57:34 +0200 (CEST) Subject: [pypy-svn] r25124 - pypy/dist/pypy/objspace Message-ID: <20060329175734.1E41E100B9@code0.codespeak.net> Author: auc Date: Wed Mar 29 19:57:32 2006 New Revision: 25124 Modified: pypy/dist/pypy/objspace/logic.py Log: misc fixes Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Wed Mar 29 19:57:32 2006 @@ -192,7 +192,7 @@ def wait__Var(space, w_self): while 1: #print " :wait", w_self - if space.is_true(is_free(space, w_self)): + if space.is_true(space.is_free(w_self)): if not have_uthreads(): raise OperationError(space.w_RuntimeError, space.wrap("trying to perform an operation on an unbound variable")) @@ -235,7 +235,7 @@ def wait_needed__Var(space, w_self): while 1: print " :needed", w_self - if space.is_true(is_free(space, w_self)): + if space.is_true(space.is_free(w_self)): if w_self.w_needed: break # we're done if not have_uthreads(): @@ -290,20 +290,30 @@ return space.newbool(isinstance(w_var.w_bound_to, W_Var)) app_is_free = gateway.interp2app(is_free) - is_free_mm = StdObjSpaceMultiMethod('is_free', 1) is_free_mm.register(is_free__Root, W_Root) is_free_mm.register(is_free__Var, W_Var) all_mms['is_free'] = is_free_mm -def is_bound(space, w_var): - return space.newbool(not space.is_true(is_free(space, w_var))) +def is_bound(space, w_obj): + return space.is_bound(w_obj) + +def is_bound__Root(space, w_obj): + return space.newbool(True) + +def is_bound__Var(space, w_var): + return space.newbool(not isinstance(w_var.w_bound_to, W_Var)) + app_is_bound = gateway.interp2app(is_bound) +is_bound_mm = StdObjSpaceMultiMethod('is_bound', 1) +is_bound_mm.register(is_bound__Root, W_Root) +is_bound_mm.register(is_bound__Var, W_Var) +all_mms['is_bound'] = is_bound_mm def alias_of(space, w_var1, w_var2): # FIXME: appears to block - assert space.is_true(is_free(space, w_var1)) - assert space.is_true(is_free(space, w_var2)) + assert space.is_true(space.is_free(w_var1)) + assert space.is_true(space.is_free(w_var2)) # w_var2 could be a right-alias of w_var2 # or the other way around w_curr = w_var1 @@ -393,7 +403,7 @@ uthread(space, space.wrap(_sleep), argument.Arguments(space, [w_2, w_barrier])) wait(space, w_barrier) - if space.is_true(is_free(space, w_2)): + if space.is_true(space.is_free(w_2)): return space.newint(1) return space.newint(2) app_wait_two = gateway.interp2app(wait_two) @@ -410,14 +420,14 @@ app_bind = gateway.interp2app(bind) def bind__Var_Var(space, w_var, w_obj): - if space.is_true(is_bound(space, w_var)): - if space.is_true(is_bound(space, w_obj)): + if space.is_true(space.is_bound(w_var)): + if space.is_true(space.is_bound(w_obj)): return unify(space, deref(space, w_var), deref(space, w_obj)) # 2. a (obj unbound, var bound) return _assign(space, w_obj, deref(space, w_var)) - elif space.is_true(is_bound(space, w_obj)): + elif space.is_true(space.is_bound(w_obj)): # 2. b (var unbound, obj bound) return _assign(space, w_var, deref(space, w_obj)) else: # 1. both are unbound @@ -426,7 +436,7 @@ def bind__Var_Root(space, w_v1, w_v2): # 3. var and value - if space.is_true(is_free(space, w_v1)): + if space.is_true(space.is_free(w_v1)): return _assign(space, w_v1, w_v2) print "uh !" fail(space, w_v1, w_v2) @@ -507,8 +517,8 @@ def unify__Var_Var(space, w_x, w_y): print " :unify of two vars" - if space.is_true(is_bound(space, w_x)): - if space.is_true(is_bound(space, w_y)): + if space.is_true(space.is_bound(w_x)): + if space.is_true(space.is_bound(w_y)): return space.unify(deref(space, w_x), deref(space, w_y)) return bind(space, w_y, w_x) @@ -518,7 +528,7 @@ def unify__Var_Root(space, w_x, w_y): print " :unify var and value" - if space.is_true(is_bound(space, w_x)): + if space.is_true(space.is_bound(w_x)): return space.unify(deref(space, w_x), w_y) return bind(space, w_x, w_y) @@ -574,7 +584,6 @@ 'setattr': 2, # instead of 3 'setitem': 2, # instead of 3 'get': 2, # instead of 3 - 'unify': 2, # ---- irregular operations ---- 'wrap': 0, 'str_w': 1, @@ -607,8 +616,8 @@ def eq(w_obj1, w_obj2): if space.is_true(space.is_nb_(w_obj1, w_obj2)): return space.newbool(True) - if space.is_true(is_free(space, w_obj1)): - if space.is_true(is_free(space, w_obj2)): + if space.is_true(space.is_free(w_obj1)): + if space.is_true(space.is_free(w_obj2)): if space.is_true(alias_of(space, w_obj1, w_obj2)): return space.newbool(True) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) @@ -625,8 +634,8 @@ def cmp(w_obj1, w_obj2): if space.is_true(space.is_nb_(w_obj1, w_obj2)): return space.newbool(0) - if space.is_true(is_free(space, w_obj1)): - if space.is_true(is_free(space, w_obj2)): + if space.is_true(space.is_free(w_obj1)): + if space.is_true(space.is_free(w_obj2)): if space.is_true(alias_of(space, w_obj1, w_obj2)): return space.newbool(0) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) @@ -636,8 +645,8 @@ def ne(w_obj1, w_obj2): if space.is_true(space.is_nb_(w_obj1, w_obj2)): return space.newbool(False) - if space.is_true(is_free(space, w_obj1)): - if space.is_true(is_free(space, w_obj2)): + if space.is_true(space.is_free(w_obj1)): + if space.is_true(space.is_free(w_obj2)): if space.is_true(alias_of(space, w_obj1, w_obj2)): return space.newbool(False) # and just go on ... return parentfn(wait(space, w_obj1), wait(space, w_obj2)) @@ -707,7 +716,12 @@ setattr(space, name, boundmethod) # store into 'space' instance # /multimethod hack - is_nb_ = space.is_ # capture the original is_ op (?) + # provide a UnificationError exception + space.ExceptionTable.append('UnificationError') + space.ExceptionTable.sort() # hmmm + + # capture the original is_ op (?) + is_nb_ = space.is_ space.is_nb_ = is_nb_ space.setitem(space.builtin.w_dict, space.wrap('newvar'), From tismer at codespeak.net Wed Mar 29 20:57:36 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 29 Mar 2006 20:57:36 +0200 (CEST) Subject: [pypy-svn] r25126 - pypy/dist/pypy/translator/c/test Message-ID: <20060329185736.624ED100BA@code0.codespeak.net> Author: tismer Date: Wed Mar 29 20:57:33 2006 New Revision: 25126 Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py Log: small glitch Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Wed Mar 29 20:57:33 2006 @@ -88,7 +88,8 @@ def wrap_obj(thing): res = fetch_pywrapper(thing) if res is None: - return create_pywrapper(thing) + res = create_pywrapper(thing) + return res def unwrap_obj(pyobj, typ): RaiseNameError From ericvrp at codespeak.net Wed Mar 29 21:47:32 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 29 Mar 2006 21:47:32 +0200 (CEST) Subject: [pypy-svn] r25127 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060329194732.340F4100BF@code0.codespeak.net> Author: ericvrp Date: Wed Mar 29 21:47:31 2006 New Revision: 25127 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: My Tokyo dates Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Wed Mar 29 21:47:31 2006 @@ -8,9 +8,9 @@ ==================== ============== ===================== Name Arrive/Depart Accomodation ==================== ============== ===================== -Beatrice D?ring 21/4-25/4 +Beatrice D?ring 21/4 - 25/4 Christian Tismer -Eric van Riet Paap +Eric van Riet Paap 18/4 - 1/5 ? Jacob Hall?n Laura Creighton Anders Lehmann 23/4 - 1/5 ? From arigo at codespeak.net Thu Mar 30 12:32:18 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 30 Mar 2006 12:32:18 +0200 (CEST) Subject: [pypy-svn] r25136 - pypy/dist/pypy/jit Message-ID: <20060330103218.B4B91100C4@code0.codespeak.net> Author: arigo Date: Thu Mar 30 12:32:17 2006 New Revision: 25136 Modified: pypy/dist/pypy/jit/hintrtyper.py pypy/dist/pypy/jit/rtimeshift.py Log: Quick fix for a failing test. Modified: pypy/dist/pypy/jit/hintrtyper.py ============================================================================== --- pypy/dist/pypy/jit/hintrtyper.py (original) +++ pypy/dist/pypy/jit/hintrtyper.py Thu Mar 30 12:32:17 2006 @@ -335,7 +335,7 @@ def create(self, hop): if self.typedesc is None: T = self.original_concretetype.TO - self.typedesc = rtimeshift.ContainerTypeDesc.make(T) + self.typedesc = rtimeshift.StructTypeDesc.make(T) ts = self.timeshifter return hop.llops.genmixlevelhelpercall(self.typedesc.ll_factory, [], [], ts.s_RedBox) Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Thu Mar 30 12:32:17 2006 @@ -262,7 +262,7 @@ rgenop.constTYPE(RESULT)) return VarRedBox(genvar) -class ContainerTypeDesc(object): +class StructTypeDesc(object): _type_cache = weakref.WeakKeyDictionary() def __init__(self, TYPE): @@ -270,26 +270,23 @@ self.PTRTYPE = lltype.Ptr(TYPE) self.gv_type = rgenop.constTYPE(self.TYPE) self.gv_ptrtype = rgenop.constTYPE(self.PTRTYPE) - # XXX only for Struct so far self.fielddescs = [StructFieldDesc.make(self.PTRTYPE, name) for name in TYPE._names] defls = [] - for name in TYPE._names: - FIELDTYPE = TYPE._flds[name] - if isinstance(FIELDTYPE, lltype.ContainerType): - subtypedesc = ContainerTypeDesc.make(FIELDTYPE) - defaultbox = VirtualRedBox(subtypedesc) + for desc in self.fielddescs: + if desc.inlined_typedesc is not None: + defaultbox = VirtualRedBox(desc.inlined_typedesc) else: - defaultvalue = FIELDTYPE._defl() + defaultvalue = desc.RESTYPE._defl() defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) defls.append(defaultbox) self.content_boxes = defls def make(T): try: - return ContainerTypeDesc._type_cache[T] + return StructTypeDesc._type_cache[T] except KeyError: - desc = ContainerTypeDesc._type_cache[T] = ContainerTypeDesc(T) + desc = StructTypeDesc._type_cache[T] = StructTypeDesc(T) return desc make = staticmethod(make) @@ -334,9 +331,12 @@ self.fieldname = fieldname self.gv_fieldname = rgenop.constFieldName(fieldname) self.fieldindex = operator.indexOf(PTRTYPE.TO._names, fieldname) - if isinstance(RES1, lltype.ContainerType): + if isinstance(RES1, lltype.Struct): # inlined substructure - self.inlined_typedesc = ContainerTypeDesc.make(RES1) + self.inlined_typedesc = StructTypeDesc.make(RES1) +## elif isinstance(RES1, lltype.Array): +## # inlined array XXX in-progress +## self.inlined_typedesc = ArrayTypeDesc.make(RES1) else: self.inlined_typedesc = None From auc at codespeak.net Thu Mar 30 17:49:09 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 30 Mar 2006 17:49:09 +0200 (CEST) Subject: [pypy-svn] r25146 - pypy/dist/pypy/doc Message-ID: <20060330154909.A89F4100D0@code0.codespeak.net> Author: auc Date: Thu Mar 30 17:49:08 2006 New Revision: 25146 Modified: pypy/dist/pypy/doc/constraints-and-logic.txt Log: update reflecting current state of affairs ... Modified: pypy/dist/pypy/doc/constraints-and-logic.txt ============================================================================== --- pypy/dist/pypy/doc/constraints-and-logic.txt (original) +++ pypy/dist/pypy/doc/constraints-and-logic.txt Thu Mar 30 17:49:08 2006 @@ -11,38 +11,35 @@ ----- This document tries to shed some light on integration of logic and -constraint programming into Python using the PyPy -framework. +constraint programming into Python using the PyPy framework. + +This takes place in Working Packages 09 and 10 of the EU PyPy funding +project. The logic and constraint programming features are to be added +to PyPy (WP9). An ontology library will be provided and will serve as +our first use case for logic programming. PyPy has been progressively equiped with a parser and compiler flexible enough that it is hoped that developpers can leverage it to extend the language *at runtime*. This is quite in the spirit of Lisp -macros, if not the exact manner. - -This takes place in Working Packages 09 and 10 of the EU PyPy funding -project. It is expected that an aspect oriented programming toolkit be -built using the compiler and parser infrastructure (WP10), and that the -logic and constraint programming features be added to PyPy (WP9). An -ontology library will be provided and will serve as our first use -case for logic programming. +macros, if not the exact manner. It is expected that an aspect +oriented programming toolkit be built using the compiler and parser +infrastructure (WP10). This will serve the needs of WP9. Clarifications -------------- This work was described as integration of logic programming *and* -constraint programming into PyPy. Both are obviously related but we -don't know if they will share, in PyPy, the same syntax and the same -machinery. - -Also it has been said that CLP will be inspired from what is done in -the Oz programming language (http://www.mozart-oz.org/), which -provides different programming 'paradigms' with a very well -thought-out integration between said paradigms. For instance, -imperative features can be mixed, to some extent, with logic -programming (the later can be 'embedded' in the former); or constraint -programming goes with stateless concurrency, another important feature -of Oz. We still don't know to what extent the Oz level of integration -will be pursued in the context of PyPy, esp. WP 9 and 10. +constraint programming into PyPy. Both are obviously related and we +have settled on the concurrent logic and constraint programing (CCLP) +model present in the Oz programing language. It allows to write +logic (Prolog-style) programs and to use constraint solving +techniques in an integrated manner (as opposed to the use of an +external toolkit with high impedance mismatch between language runtime +and constraint solving package). The relational way will be built on +the constraint solving machinery (much like, in Oz, the *choice* +operator is built on top of *choose*). + +This will allow Lastly, here we mainly discuss syntactical issues: those are probably the least difficult aspects of getting CLP into python; getting an @@ -54,18 +51,19 @@ In constraint programming, a 'problem' is a set of variables, their (finite discrete) domains, and the constraints that restrict their -possible values. When all these have been given to a constraint -solver, it is possible to find all possible solutions, that is the -sets of valuations that satisfies simultaneously all constraints. The -solver is solely responsible for finding solutions (or lack thereof). +possible values (or define the relations between the values). When all +these have been given to a constraint solver, it is possible to find +all possible solutions, that is the sets of valuations that satisfies +simultaneously all constraints. The solver is solely responsible for +finding solutions (or lack thereof). Overview in python ------------------ At the time being, there exists a *constraints* package made by -Logilab and written in pure python, which implements the solver found -in Mozart (the reference Oz implementation). We use it to illustrate -where we want to go, syntactically-wise. +Logilab and written in pure python, which implements some parts of the +solver found in Mozart (the reference Oz implementation). We use it to +illustrate where we want to go, syntactically-wise. Let's start with a quite standard example (the problem being solved here is fully described on @@ -130,14 +128,16 @@ Specifiying a constraint is clunky : variables and operator have to be provided separately, and the operator has to be a string. This last -restriction because Python doesn't allow passing builtin (infix) +restriction because Python doesn't allow passing builtin infix operators as functional parameters. +(the following sub-chapters are considered deprecated) + Special operator for CLP variable bindings ------------------------------------------ -First, promote variables from third-class to second-class -citizenry. Be able to write something like:: +First, promote variables to second-class citizenry. Be able to write +something like:: domain = [(room,slot) for room in ('room A','room B','room C') @@ -214,142 +214,218 @@ other hand, the lexically bounded mini-language proposed above helps solve this more uniformly. -Logic Programming, Prolog-style -=============================== - -Good old logic programming has an already long syntactic tradition; we -should probably not try to evade it too much. Thus we propose again a -mini-language embedding horn-clauses and logic stuff into 'normal' -(unsuspecting) Python programs. - -Existing python/prolog projects can be found at : -http://christophe.delord.free.fr/en/pylog/ and -http://aima.cs.berkeley.edu/python/logic.html. There might be more of -them. - - -Databases and Requests ----------------------- - -Databases contain facts, rules and requests:: - - >>> database Numbers: # we def a logic db and enter prolog space - ... natural(z) - ... natural(s(X)) if natural(X) - ... r1: natural(s(s(s(z)))) # kind of named request - ... - >>> Numbers - - >>> Numbers = 42 - NotAssignable exception, etc. - - -Integration in Python ---------------------- - -:: - - # databases as first class objects - get_logic_databases() # -> [Numbers] - - # return values in Python space - d1 = get_logic_databases()[0] - d1.ask('r1') -> True +Logic Programming, Prolog and Oz-style +====================================== - # extending an existing database - database Numbers: # adds up to existing Numbers db (eyebrows raise) - pair(z) - pair(s(s(X))) if pair(X) +Integrated search seamlessly into an already grown up imperative +programming language might cause some headaches. For instance, in the +perspective of benefiting from the Prolog way of doing logic +programming, we considered embedding a specific mini-language into +Python with strong and well-defined borders between the logic world +and the 'normal', or usual imperative world of standard Python. + +Such a twist might be not needed, fortunately. Designers of Oz have +devised another way of doing logic programming that is certainly much +more easily integrable into current Python than bolting Prolog into +it. + +Criticism of Prolog +------------------- + +The Prolog-style for logic programming, while successfully applied to +many real-world problems, is not without defects. These can be +summarized as the following : + +* Prolog is a compromise between relational and algorithmic style of + programming. It does not go far enough on the side of + relations/constraints (horn clauses have limited expressiveness) and + makes unnatural to write algorithmic (non-searching) code. + +* it is completely unsuitable to concurrent programming, which is + becoming more regarded as new languages allow to do it with + high-level, hassle-free constructs, and is a necessity to build + reactive applications. + + +Integration in PyPy +------------------- + +From the PyPy sprint in Belgium that was focused on constraint and +logic programming emerged an implementation of a so-called 'Logic +Objectspace' which extends PyPy's standard object space implementing +standard Python operations with two things : + +* micro threads (which despite their names are merely, currently, + greenlets, that is a kind of coroutine) + +* Logic Variables, that is a new datatype acting as a box for normal + Python values. + + +Logic Variables +--------------- + +Logic variables have two states : free and bound. A bound logic +variable is indistinguishable from a normal Python value which it +wraps. A free variable can only be bound once (it is also said to be a +single-assignment variable). + +The operation that binds a logic variable is known as +"unification". Unify is an operator that takes two arbitrary data +structures and tries to check if they are the same, much in the sense +of the == operator, but with one twist : unify is a "destructive" +operator when it comes to logic variables. + +Unifying one unbound variable with some value means assigning the +value to the variable (which then satisfies equalness), unifying two +unbound variables aliases them (they are constrained to reference the +same -future- value). Thus unify can change the state of the world and +raises an UnificationError exception whenever it fails, instead of +returning False like an equality predicate. + +Assignment or aliasing of variables is provided by the 'bind' operator. + +Threads and dataflow synchronisation +------------------------------------ + +When a piece of code tries to access a free logic variable, the thread +in which it runs is blocked (suspended) until the variable becomes +bound. This behaviour is known as "dataflow synchronization" and +mimics exactly the dataflow variables from Oz. With respect to +behaviour under concurrency conditions, logic variables come with two +operators : + +* wait : this suspends the current thread until the variable is bound, + it returns the value otherwise (in the logic objectspace, all + operators make an implicit, transparent wait on their value arguments) + +* wait_needed : this suspends the current thread until the variable + has received a wait message. It has to be used explicitely, + typically by a producer thread that wants to produce data only when + needed. + +* bind : binding a variable to a value will make runnable all threads + suspended this variable. + +Wait and wait_needed allow to write efficient lazy evaluating code. + +Relation with logic programming +------------------------------- + +All of this is not sufficient without a specific non-deterministic +primitive operator added to the language. In Oz, the 'choice' operator +allows to statically enumerate a set of possible actions, leaving the +actual decision to choose between several branches to the solver. + +Let us look at a small relational program written respectively in +Prolog, Oz and extended Python. + +Prolog : + + Soft(beige). + Soft(coral). + Hard(mauve). + Hard(ochre). + + Contrast(C1, C2) :- Soft(C1), Hard(C2). + Contrast(C1, C2) :- Hard(C1), Soft(C2). + + Suit(Shirt, Pants, Socks) :- Contrast(Shirt, Pants), + Contrast(Pants, Socks), Shirt != Socks. + +Oz : + + fun {Soft} choice beige [] coral end end + fun {Hard} choice mauve [] ochre end end + + proc {Contrast C1 C2} + choice C1={Soft} C2={Hard}[] C1={Hard} C2={Soft} end + end + + fun {Suit} + Shirt Pants Socks + in + {Contrast Shirt Pants} + {Contrast Pants Socks} + if Shirt==Socks then fail end + suit(Shirt Pants Socks) + end + +Python : + + def soft(): + choice: 'beige' or: 'coral' + + def hard(): + choice: 'mauve' or: 'ochre' + + def contrast(C1, C2): + choice: + unify(C1, soft()) + unify(C2, hard()) + or: + unify(C1, hard()) + unify(C2, soft()) + + def suit(): + let Shirt, Pants, Socks: + contrast(Shirt, Pants) + contrast(Pants, Socks) + if Shirt == Socks: raise UnificationError + return (Shirt, Pants, Socks) + +Since our variables (those created by the let declaration) really are +logic variables, and thus can be assigned to only once, the solver +must take some special measure to get all the solutions. The trick is +that the solver uses the Computation Space machinery for constraint +solving. Basically, a computation space is like an independant world +in which a specific, unique combination of choices will be tried and +eventually a -locally- unique solution be produced. The solver uses as +many computation spaces as neccessary to eventually enumerate all +possible solutions. - # database acquisition (inheritance ?) - database Ratios(Numbers): - pass - # adding rules and requests from Python space - d2 = get_logic_databases[1] # the Ratios db - d2.add_rule('ratio(X,Y) if Y != z, natural(X), natural(Y)') - - d2.add_request('r2', 'ratio(s(z),toto)') - d2.ask('r2') -> False +Done and To Do +============== +What has been done +------------------ -Thus, the logic and Python stuff are cleanly separated, and of course -we forbid lexical capture as in:: - - z = 42 - database Numbers: - natural(z) - -A (maybe) nicer way to ask could be:: - - database Family : - - father(jean, pierre) - father(paul, jean) - grandfather(X,Y) if father(X,Z) and father(Z,Y) - - Family.grandfather(jean, A) - - -Conclusion ----------- - -Syntax is not all-important but can touch on the nerves of some. It -sometimes involves relogious arguments. We hope to irritate none with -this proposal; we merely expect counter-proposals or more detailed -proposals or agreement or just indiference on this. +For constraint programming: +* A prototype concurrent solver using Computation Spaces, CPython + threads and the existing logilab constraints package has been built + and shown to work (note that it is not 100% complete in the sense + that the part that allows logic programming to be used is not + there. Only recently has this been figured out). -CLP and Oz -========== +* A simulation of dataflow/logic variables has been built. -The Oz programming language is and will be a driving inspiration for -all deep integration work of CLP. Logilab constraints pure python -package already implements search according to Oz (without the -concurrency parts). +For logic programming: -(don't forget to have a serious look at Screamer/CL) +* A prototype logic object space has been built, which provides + integrated logic variables with dataflow semantics, an incomplete + implementation of micro threads, -What shall be done ------------------- +What needs to be done +--------------------- For constraint programming: -* Adapt the core algorithms from logilab.constraints to RPython -* Stuff it into PyPy -* Enhance (tm) it with concurrency aspects (needs preemptive - threading) +* Reimplement the computation space as an entity of the logic object + space (we think that reusing thread pickling abilities would be an + interesting start). + +* Adapt the core algorithms to RPython Logic programming: -* Investigate how much of above can be reused -* Pick a strategy (reuse constraints or implement unification) -* Implement deep into PyPy +* Provide a basic solver (depth-first), and a working choose() space + operator to allow search as provided in logic programming. For both: -* Adapt the parser/lexer to the syntactic requirements - - -Ideas of testbeds -================= - -try to use logic related features in all of these python projects to -make sure of the design and implementation of logic in pypy. - -- rdflib.sparql an implementation of W3C's SPARQL language coupled - with redfoot. - http://rdflib.net/2005/09/10/rdflib-2.2.2/html/public/rdflib.sparql-module.html - -- cwm a rule-based engine for rdf inferencing - http://www.w3.org/2000/10/swap/doc/cwm.html - -- pychinko an implementation of RETE algorithm for rule-based systems - http://www.mindswap.org/~katz/pychinko/ - http://en.wikipedia.org/wiki/Rete_algorithm +* Adapt the parser/lexer to the syntactic requirements (which should + be light). -- pylint: using constraints to generate design-related comments and - warnings is done in SOUL or doable with pyontology - http://www.logilab.org/projects/pylint -- pyontology. DFKI's OWL manipulation tool (see svn) From ale at codespeak.net Thu Mar 30 18:45:01 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 30 Mar 2006 18:45:01 +0200 (CEST) Subject: [pypy-svn] r25148 - pypy/extradoc/minute Message-ID: <20060330164501.80398100D1@code0.codespeak.net> Author: ale Date: Thu Mar 30 18:45:00 2006 New Revision: 25148 Added: pypy/extradoc/minute/pypy-sync-2006-03-30.txt Log: Minutes of #pypy-sync meeting Added: pypy/extradoc/minute/pypy-sync-2006-03-30.txt ============================================================================== --- (empty file) +++ pypy/extradoc/minute/pypy-sync-2006-03-30.txt Thu Mar 30 18:45:00 2006 @@ -0,0 +1,154 @@ +what: weekly pypy-sync meeting +where: #pypy-sync on freenode +when: 2006-03-30, 5pm Central European Time for 30 minutes +who: all active PyPy developers + +topics: + +- activity reports +- the status of uthreads. It is needed by the logic implementation. +- is it premature to think about setting up a buildbot, and is builbot the right tool + +- next pypy-sync meeting. I propose that the next pypy-sync meeting will be at april 20. due to Leysin sprint and easter. + + +Cheers, +ale + +16:45 +stedi67 has quit the server saying: Remote closed the connection +stedi67 has joined the channel +16:55 +ericvrp has joined the channel +17:00 +arigo has joined the channel +auc has joined the channel +arigo: hi +auc: hi +stedi67: hallo +aleale: hi +aleale: I guess arre, pedronis are not coming. hpk ? +ericvrp: hi +Gromit has joined the channel +aleale: I think we can start with our 3 lines +auc: LAST : refactoring of the Logic Space +auc: NEXT : choice : integration of constraint code into PyPy's core, or making logic space compilable +auc: BLOCKER : logic space -> bug-free greenlets/threads, constraints -> picklable greenlets/threads +aleale: PREV: trying to understand OWL semanticsNEXT: Sprintblockers: too small mental bandwith +ericvrp: LAST: pyllvm using ctypes +ericvrp: NEXT: more of that and write tools to aid C++ -> C api +ericvrp: BLOCKERS: - +arigo: PREV: a bit on the JIT +arigo: NEXT: more on the JIT, before the official sprint begins +arigo: BLOCKERS: - +aleale: any one else ? mwh is on holliday I guess +stedi67: LAST: complex/set impl +Gromit: PREV: trying to register ctypes structures with the extrigistry +stedi67: NEXT: refactoring of these +17:05 +stedi67: BLOCKERS: my brain +aleale: The only blocker we can address is actually the next topic +aleale: - the status of uthreads. It is needed by the logic implementation. +Gromit: NEXT: trying harder +Gromit: BLOCKERS: not mucht time till the sprint +aleale: Does anyone have a comment on the status ? +auc: yes +auc: we will need working greenlets real soon now +cfbolz has joined the channel +auc: true micro threads can wait +auc: and could be postponed for a while +arigo: good to know +aleale: hi Carl +cfbolz: sorry +arigo: but it seems that nobody here can comment on the current status of the greenlets +auc: afaik samuele or christian could +aleale: Carl and Samuele did something in Belgium +auc: samuele seems to know what's missing to have them working +auc: maybe carl knows too +cfbolz: arigo: I can a little bit +auc: aleale: that's what i've been refactoring +cfbolz: there are still problems with the framestate, I think +cfbolz: plus, they are not really well exposed to applevel +nikh has joined the channel +cfbolz: but the basic mechanisms are there and work well +nikh: hi! sorry for being late ... +cfbolz: the most work will be to make nice interfaces +auc: cfbolz: it's quite easy to hit the framestate stuff +17:10 +cfbolz: yes +cfbolz: christian knows how to solve it, I think +auc: what are your thoughts abou nice interfaces ? +cfbolz: we have to get him to do it +auc: (the current one ... sort of satisfies me) +cfbolz: auc: well, I think it makes sense with interfaces that exist already +cfbolz: like the stackless module, greenlets +cfbolz: coroutines +cfbolz: auc: logic variables are in a way another interface to microthreads +auc: hmm +auc: not sure i understand this +cfbolz: why? +auc: but i personnally see no special problem with this interface stuff ... +cfbolz: well +cfbolz: it is part of wp7 +auc: will christian be at leysin ? +arigo: who knows? +cfbolz: nobody +auc: he seems to be quite busy with stuff unrelated with coroutines/stackless/... +aleale: He hasnot put his name in people.txt yet +ericvrp: he mentioned to me this he probably will not be able to make it to Leysin +auc: so i read it as : won't be there +Gromit: according to my last chat with him, chris will be at leysin +Gromit: ericvrp, sigh +arigo: that's what I meant by "who knows" +cfbolz: +ericvrp: Gromit, so we are still unsure +Gromit: yep +cfbolz: I advise to put it into the minutes that work on coroutines is getting essential +17:15 +Gromit: managing programmers is like herding cats +auc: he doesn't show up to often on #pypy either +auc: s/to/too +aleale: I will put it in the minutes that we need Christian to look into this +cfbolz: auc: he does, just at american times +aleale: Next topic ? +cfbolz: fine with me +aleale: Buildbot - to premature ? not the right tool ? +aleale: s/to/too +cfbolz: I think it might not perfectly fit our problem +arigo: what is precisely our problem? +aleale: Many options that needtesting +aleale: but maybe we should wait till we closer at be "production" ready +cfbolz: I know that holger has worked on some stuff in that direction recently for hp +cfbolz: using execnet +aleale: cool +17:20 +cfbolz: I guess our problem is that we don't know the problem we want to solve yet +cfbolz: who proposed the topic? +aleale: I did - had to invent some topic +auc: pypy is traversing some sort of crisis ... +cfbolz: auc: huh? why? +auc: lack of topic at pypy-sync is a sure sign ... +auc: +cfbolz: rather a lack of activity, I would say +Gromit: yep, cfbolz +cfbolz: arigo: but indeed, sometimes it would be cool to be able to do translation/tests faster. although it has not become a fundamental problem that hinders work +auc: does this mean we are done for today ? +aleale: One more topic +aleale: next pypy-sync meeting. I propose that the next pypy-sync meeting will be at april 20. due to Leysin sprint and easter. +cfbolz: when is easter? +nikh: easter is 16./17. april +arigo: 16th +cfbolz: ah +17:25 +aleale: Who will moderate it ? I am not able to do it +auc: i can do that probably +cfbolz: great +aleale: I n Denmark the 13/14 is a holiday too +aleale: great +aleale: Anymore topics ( my list is exhausted )? +aleale: else: See you in Leysin +Gromit: bye +Gromit has left the channel saying: "Leaving" +auc: bye +ericvrp: bye + From tismer at codespeak.net Thu Mar 30 21:01:35 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 30 Mar 2006 21:01:35 +0200 (CEST) Subject: [pypy-svn] r25159 - pypy/dist/pypy/translator/c/test Message-ID: <20060330190135.983C4100D0@code0.codespeak.net> Author: tismer Date: Thu Mar 30 21:01:32 2006 New Revision: 25159 Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py Log: getting closer to a complete (two-way) wrapper. I have to say: writing assembly code is similar but simpler :-) Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Thu Mar 30 21:01:32 2006 @@ -19,7 +19,7 @@ missing = [object] * (func.func_code.co_argcount - len(argstypelist)) return missing + argstypelist -def get_compiled_module(func, view=conftest.option.view, inline_threshold=1, +def get_compiled_module(func, view=conftest.option.view, inline_threshold=0*1, use_boehm=False, exports=[]): from pypy.translator.translator import TranslationContext from pypy.translator.backendopt.all import backend_optimizations @@ -79,20 +79,12 @@ # stubs for special annotation/rtyping -def create_pywrapper(thing): - RaiseNameError - -def fetch_pywrapper(thing): - RaiseNameError - def wrap_obj(thing): - res = fetch_pywrapper(thing) - if res is None: - res = create_pywrapper(thing) - return res + RaiseNameError def unwrap_obj(pyobj, typ): RaiseNameError +unwrap_obj._annspecialcase_ = 'specialize:arg(1)' def call_destructor(thing, savedrepr): ll_call_destructor(thing, savedrepr) @@ -108,11 +100,53 @@ This was only possible with Samuele's hints. """ -def rtype_wrap_object_create(hop): +def rtype_destruct_object(hop): + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value + if '_wrapper_' in repr.allinstancefields: + null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) + repr.setfield(v_any, '_wrapper_', null, hop.llops) + hop.genop('gc_unprotect', [v_any]) + +def rtype_unwrap_object(hop): + v_pyobj, v_type = hop.inputargs(*hop.args_r) + v_adr = hop.llops.gencapicall('PyCObject_AsVoidPtr', [v_pyobj], + resulttype=hop.r_result) + hop.genop('gc_protect', [v_adr]) + return v_adr + +def rtype_wrap_object(hop): v_any, = hop.inputargs(*hop.args_r) + repr = hop.args_r[0] + c_repr = hop.inputconst(lltype.Void, repr) + if '_wrapper_' in repr.allinstancefields: + return hop.gendirectcall(ll_wrap_object, v_any, c_repr) + else: + return hop.gendirectcall(create_pywrapper, v_any, c_repr) + +def ll_wrap_object(obj, repr): + ret = fetch_pywrapper(obj, repr) + if not ret: + ret = create_pywrapper(obj, repr) + return ret + +def create_pywrapper(thing, sr): + return ll_create_pywrapper(thing, sr) + +def ll_create_pywrapper(thing, sr): + return 42 + +def fetch_pywrapper(thing, sr): + return ll_fetch_pywrapper(thing, sr) + +def ll_fetch_pywrapper(thing): + return 42 + +def rtype_wrap_object_create(hop): + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value f = call_destructor hop.genop('gc_protect', [v_any]) - repr = hop.args_r[0] ARGTYPE = repr.lowleveltype reprPBC = hop.rtyper.annotator.bookkeeper.immutablevalue(repr) fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARGTYPE, reprPBC]) @@ -126,28 +160,14 @@ return res def rtype_wrap_object_fetch(hop): - v_any, = hop.inputargs(*hop.args_r) - repr = hop.args_r[0] + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value if '_wrapper_' in repr.allinstancefields: return repr.getfield(v_any, '_wrapper_', hop.llops) else: null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) return null -def rtype_destruct_object(hop): - v_any, c_spec = hop.inputargs(*hop.args_r) - repr = c_spec.value - if '_wrapper_' in repr.allinstancefields: - null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) - repr.setfield(v_any, '_wrapper_', null, hop.llops) - hop.genop('gc_unprotect', [v_any]) - -def rtype_unwrap_object(hop): - v_pyobj, v_type = hop.inputargs(*hop.args_r) - v_adr = hop.llops.gencapicall('PyCObject_AsVoidPtr', [v_pyobj], - resulttype=hop.r_result) - hop.genop('gc_protect', [v_adr]) - return v_adr """ The following registers the new mappings. The registration @@ -160,25 +180,44 @@ """ def do_register(t): + seen = {} def compute_annotation_unwrap(s_wrapper, s_class_or_inst): if hasattr(s_class_or_inst, 'classdef'): classdef = s_class_or_inst.classdef + elif hasattr(s_class_or_inst, 'descriptions'): + descs = s_class_or_inst.descriptions + print 1000*"X" + print descs + print seen + for desc in descs.keys(): + classdef = desc.getuniqueclassdef() + if classdef not in seen: + seen[classdef] = True + break + else: + if len(descs) > 1: + raise ValueError, ("had a problem finding the right class", descs) else: classdef = t.annotator.bookkeeper.getuniqueclassdef(s_class_or_inst.const) + seen[classdef] = True return annmodel.SomeInstance(classdef) - extregistry.register_value(create_pywrapper, - compute_result_annotation=annmodel.SomeObject(), + extregistry.register_value(ll_create_pywrapper, + compute_result_annotation=annmodel.SomePtr(lltype.Ptr(lltype.PyObject)), specialize_call=rtype_wrap_object_create) - extregistry.register_value(fetch_pywrapper, - compute_result_annotation=annmodel.SomeObject(), + extregistry.register_value(ll_fetch_pywrapper, + compute_result_annotation=annmodel.SomePtr(lltype.Ptr(lltype.PyObject)), specialize_call=rtype_wrap_object_fetch) extregistry.register_value(ll_call_destructor, - compute_result_annotation=lambda *args:None, + compute_result_annotation=lambda *args: None, specialize_call=rtype_destruct_object) + extregistry.register_value(wrap_obj, + compute_result_annotation=annmodel.SomeObject(), + specialize_call=rtype_wrap_object) + extregistry.register_value(unwrap_obj, compute_result_annotation=compute_annotation_unwrap, specialize_call=rtype_unwrap_object) @@ -248,9 +287,11 @@ def call_wrap_obj(inst): return wrap_obj(inst) +call_wrap_obj._annspecialcase_ = 'specialize:argtype(0)' def call_unwrap_obj(pyobj, klass): return unwrap_obj(pyobj, klass) +call_unwrap_obj._annspecialcase_ = 'specialize:arg(1)' def democlass_helper_sub(a, b): # prevend inlining @@ -260,6 +301,10 @@ pyobj = call_wrap_obj(inst) obj = call_unwrap_obj(pyobj, DemoClass) ret = obj.demo() + inst = DemoSubclass(a, b, 42) + pyobj = call_wrap_obj(inst) + obj = call_unwrap_obj(pyobj, DemoSubclass) + ret = obj.demo() return ret def democlass_helper(a=int, b=int): @@ -275,7 +320,7 @@ # creating an object, wrapping, unwrapping, call function, check whether __del__ is called def test_wrap_call_dtor(): - f = getcompiled(democlass_helper, use_boehm=not True, exports=[DemoClass]) + f = getcompiled(democlass_helper, use_boehm=not True, exports=[DemoSubclass]) ret = f(2, 3) if P: print ret assert ret[0] == 1 From tismer at codespeak.net Thu Mar 30 22:13:14 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 30 Mar 2006 22:13:14 +0200 (CEST) Subject: [pypy-svn] r25168 - pypy/extradoc/sprintinfo/tokyo Message-ID: <20060330201314.871EB100D5@code0.codespeak.net> Author: tismer Date: Thu Mar 30 22:13:12 2006 New Revision: 25168 Modified: pypy/extradoc/sprintinfo/tokyo/people.txt Log: coming! Modified: pypy/extradoc/sprintinfo/tokyo/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/tokyo/people.txt (original) +++ pypy/extradoc/sprintinfo/tokyo/people.txt Thu Mar 30 22:13:12 2006 @@ -9,7 +9,7 @@ Name Arrive/Depart Accomodation ==================== ============== ===================== Beatrice D?ring 21/4 - 25/4 -Christian Tismer +Christian Tismer 22/4 - 30/4 Eric van Riet Paap 18/4 - 1/5 ? Jacob Hall?n Laura Creighton From tismer at codespeak.net Thu Mar 30 22:15:01 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 30 Mar 2006 22:15:01 +0200 (CEST) Subject: [pypy-svn] r25169 - pypy/dist/pypy/translator/c/test Message-ID: <20060330201501.CB268100D5@code0.codespeak.net> Author: tismer Date: Thu Mar 30 22:14:59 2006 New Revision: 25169 Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py Log: specializing unwrap on class argument Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Thu Mar 30 22:14:59 2006 @@ -180,26 +180,12 @@ """ def do_register(t): - seen = {} - def compute_annotation_unwrap(s_wrapper, s_class_or_inst): - if hasattr(s_class_or_inst, 'classdef'): - classdef = s_class_or_inst.classdef - elif hasattr(s_class_or_inst, 'descriptions'): - descs = s_class_or_inst.descriptions - print 1000*"X" - print descs - print seen - for desc in descs.keys(): - classdef = desc.getuniqueclassdef() - if classdef not in seen: - seen[classdef] = True - break - else: - if len(descs) > 1: - raise ValueError, ("had a problem finding the right class", descs) - else: - classdef = t.annotator.bookkeeper.getuniqueclassdef(s_class_or_inst.const) - seen[classdef] = True + def compute_annotation_unwrap(s_wrapper, s_class): + assert hasattr(s_class, 'descriptions'), 'need a class in unwrap 2nd arg' + descs = s_class.descriptions + assert len(descs) == 1, 'missing specialisation, classdesc not unique!' + for desc in descs.keys(): + classdef = desc.getuniqueclassdef() return annmodel.SomeInstance(classdef) extregistry.register_value(ll_create_pywrapper, @@ -310,7 +296,7 @@ def democlass_helper(a=int, b=int): delmonitor.reset() ret = democlass_helper_sub(a, b) - return delmonitor.report(), ret, 42 # long(42) # this creates ATM a bad crash + return delmonitor.report(), ret, long(42) def democlass_helper2(a=int, b=int): self = DemoClass(a, b) @@ -326,7 +312,7 @@ assert ret[0] == 1 # exposing and using classes from a generasted extension module -def xtest_expose_classes(): +def test_expose_classes(): m = get_compiled_module(democlass_helper2, use_boehm=not True, exports=[ DemoClass, DemoSubclass, DemoNotAnnotated]) obj = m.DemoClass(2, 3) From tismer at codespeak.net Fri Mar 31 03:29:21 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 31 Mar 2006 03:29:21 +0200 (CEST) Subject: [pypy-svn] r25171 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20060331012921.DEEB5100D6@code0.codespeak.net> Author: tismer Date: Fri Mar 31 03:29:14 2006 New Revision: 25171 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py Log: two-way wrapping works internally. That is, we can wrap an instance and produce the real wrapper class. This works in the test script. Now I"m building it into rclass.py and change the generated python script. Funny, lots of internal stuff, but no C code touched at all. (will probably happen, when I optimize the internal PyCObjects away) Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Fri Mar 31 03:29:14 2006 @@ -330,8 +330,7 @@ self.rbase.setup() # # PyObject wrapper support - if (self.rtyper.needs_wrapper(self.classdef) and '_wrapper_' - not in self.rbase.allinstancefields): + if self.has_wrapper and '_wrapper_' not in self.rbase.allinstancefields: fields['_wrapper_'] = 'wrapper', pyobj_repr llfields.append(('wrapper', Ptr(PyObject))) @@ -386,6 +385,10 @@ def create_instance(self): return malloc(self.object_type, flavor=self.getflavor()) # pick flavor + def has_wrapper(self): + return self.rtyper.needs_wrapper(self.classdef) + has_wrapper = property(has_wrapper) + def get_ll_hash_function(self): if self.classdef is None: raise TyperError, 'missing hash support flag in classdef' @@ -606,10 +609,14 @@ #inst.inst___wrapper__ = nullptr(PyObject) #inst.inst_a = 42 + inst._wrapper_ = nullptr(PyObject) def rtype_destruct_object(hop): v, = hop.inputargs(*hop.args_r) - hop.gendirectcall(ll_clear_wrapper, v) + #repr = hop.args_r[0] + null = hop.inputconst(Ptr(PyObject), nullptr(PyObject)) + #repr.setfield('wrapper', null) + #hop.gendirectcall(ll_clear_wrapper, v) hop.genop('gc_unprotect', [v]) extregistry.register_value(ll_call_destructor, From tismer at codespeak.net Fri Mar 31 10:02:42 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 31 Mar 2006 10:02:42 +0200 (CEST) Subject: [pypy-svn] r25175 - in pypy/dist/pypy: rpython/lltypesystem translator/c translator/c/test translator/c/winproj/extension Message-ID: <20060331080242.0C50D100D7@code0.codespeak.net> Author: tismer Date: Fri Mar 31 10:02:37 2006 New Revision: 25175 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/translator/c/pyobj.py pypy/dist/pypy/translator/c/test/test_wrapping.py pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Log: finished two-way wrapping of objects. That is: - RPython classes can be instantiated from CPython by calling the wrapper class - return values from RPython methods or funtions automatically instantiate their wrapper class - object indentity is preserved: wrapped(rpyinst) is wrapped(rpyinst) always holds. There is one bad spot which needs support from the gc gurus: In order to clear a weak reference, I abused "bare_setfield" (blush) Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Fri Mar 31 10:02:37 2006 @@ -19,6 +19,7 @@ FuncType, Bool, Signed, functionptr, FuncType, PyObject from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython import extregistry +from pypy.annotation import model as annmodel # # There is one "vtable" per user class, with the following structure: @@ -456,14 +457,15 @@ raise MissingRTypeAttribute(attr) return self.rbase.getfield(vinst, attr, llops, force_cast=True) - def setfield(self, vinst, attr, vvalue, llops, force_cast=False): + def setfield(self, vinst, attr, vvalue, llops, force_cast=False, opname='setfield'): """Write the given attribute (or __class__ for the type) of 'vinst'.""" if attr in self.fields: mangled_name, r = self.fields[attr] cname = inputconst(Void, mangled_name) if force_cast: vinst = llops.genop('cast_pointer', [vinst], resulttype=self) - llops.genop('setfield', [vinst, cname, vvalue]) + llops.genop(opname, [vinst, cname, vvalue]) + # XXX this is a temporary hack to clear a dead PyObject else: if self.classdef is None: raise MissingRTypeAttribute(attr) @@ -592,55 +594,100 @@ # _________________________ Conversions for CPython _________________________ -def call_destructor(thing): - ll_call_destructor(thing) +def call_destructor(thing, repr): + ll_call_destructor(thing, repr) -def ll_call_destructor(thang): +def ll_call_destructor(thang, repr): return 42 # will be mapped -def ll_clear_wrapper(inst): - # Note: we must ensure to enforce creation of this extra field. - # this is done when we set up the instantiators in XXX which module??? - pass # inst.inst___wrapper__ = None - #inst.fields.au = 42 - #setattr(inst, 'inst___wrapper__', None) - #inst.inst___wrapper__ = Ptr(33)#inst.inst___wrapper__ - #p = ll_cast_to_object(inst) - - #inst.inst___wrapper__ = nullptr(PyObject) - #inst.inst_a = 42 - inst._wrapper_ = nullptr(PyObject) - def rtype_destruct_object(hop): - v, = hop.inputargs(*hop.args_r) - #repr = hop.args_r[0] - null = hop.inputconst(Ptr(PyObject), nullptr(PyObject)) - #repr.setfield('wrapper', null) - #hop.gendirectcall(ll_clear_wrapper, v) - hop.genop('gc_unprotect', [v]) + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value + if repr.has_wrapper: + null = hop.inputconst(Ptr(PyObject), nullptr(PyObject)) + # XXX this is a hack! We need an operation to remove a broken PyObject + repr.setfield(v_any, '_wrapper_', null, hop.llops, opname='bare_setfield') + hop.genop('gc_unprotect', [v_any]) extregistry.register_value(ll_call_destructor, - compute_result_annotation=lambda *args:None, + compute_result_annotation=lambda *args: None, specialize_call=rtype_destruct_object) +def create_pywrapper(thing, repr): + return ll_create_pywrapper(thing, repr) + +def ll_create_pywrapper(thing, repr): + return 42 + +def rtype_wrap_object_create(hop): + gencapi = hop.llops.gencapicall + pyptr = hop.r_result + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value + f = call_destructor + hop.genop('gc_protect', [v_any]) + ARG = repr.lowleveltype + reprPBC = hop.rtyper.annotator.bookkeeper.immutablevalue(repr) + fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARG, reprPBC]) + FUNC = FuncType([ARG, Void], Void) + c_dtor = hop.inputconst(Ptr(FUNC), fp_dtor) + res = gencapi('PyCObject_FromVoidPtr', [v_any, c_dtor], resulttype=hop.r_result) + if repr.has_wrapper: + cobj = res + c_cls = hop.inputconst(pyobj_repr, repr.classdef.classdesc.pyobj) + c_0 = hop.inputconst(Signed, 0) + res = gencapi('PyType_GenericAlloc', [c_cls, c_0], resulttype=pyptr) + c_self = hop.inputconst(pyobj_repr, '__self__') + v_result = hop.genop('setattr', [res, c_self, cobj], resulttype=pyptr) + repr.setfield(v_any, '_wrapper_', res, hop.llops) + hop.genop('gc_unprotect', [res]) # yes a weak ref + return res + +extregistry.register_value(ll_create_pywrapper, + compute_result_annotation=annmodel.SomePtr(Ptr(PyObject)), + specialize_call=rtype_wrap_object_create) + +def fetch_pywrapper(thing, repr): + return ll_fetch_pywrapper(thing, repr) + +def ll_fetch_pywrapper(thing, repr): + return 42 + +def rtype_wrap_object_fetch(hop): + v_any, c_spec = hop.inputargs(*hop.args_r) + repr = c_spec.value + if repr.has_wrapper: + return repr.getfield(v_any, '_wrapper_', hop.llops) + else: + null = hop.inputconst(Ptr(PyObject), nullptr(PyObject)) + return null + +extregistry.register_value(ll_fetch_pywrapper, + compute_result_annotation=annmodel.SomePtr(Ptr(PyObject)), + specialize_call=rtype_wrap_object_fetch) + +def ll_wrap_object(obj, repr): + ret = fetch_pywrapper(obj, repr) + if not ret: + ret = create_pywrapper(obj, repr) + return ret + class __extend__(pairtype(PyObjRepr, InstanceRepr)): def convert_from_to((r_from, r_to), v, llops): - v_adr = llops.gencapicall('PyCObject_AsVoidPtr', [v], - resulttype=r_to) + if r_to.has_wrapper: + c_self = inputconst(pyobj_repr, '__self__') + v = llops.genop('getattr', [v, c_self], resulttype=r_from) + v_adr = llops.gencapicall('PyCObject_AsVoidPtr', [v], resulttype=r_to) llops.genop('gc_protect', [v_adr]) return v_adr class __extend__(pairtype(InstanceRepr, PyObjRepr)): def convert_from_to((r_from, r_to), v, llops): - f = call_destructor - llops.genop('gc_protect', [v]) - ARGTYPE = r_from.lowleveltype - FUNCTYPE = FuncType([ARGTYPE], Void) - fp_dtor = llops.rtyper.annotate_helper_fn(f, [ARGTYPE]) - c_dtor = inputconst(Ptr(FUNCTYPE), fp_dtor) - v_result = llops.gencapicall('PyCObject_FromVoidPtr', [v, c_dtor], - resulttype=pyobj_repr) - return v_result + c_repr = inputconst(Void, r_from) + if r_from.has_wrapper: + return llops.gendirectcall(ll_wrap_object, v, c_repr) + else: + return llops.gendirectcall(create_pywrapper, v, c_repr) # ____________________________________________________________ Modified: pypy/dist/pypy/translator/c/pyobj.py ============================================================================== --- pypy/dist/pypy/translator/c/pyobj.py (original) +++ pypy/dist/pypy/translator/c/pyobj.py Fri Mar 31 10:02:37 2006 @@ -547,8 +547,9 @@ if self.shouldskipfunc(value): log.WARNING("skipped class function: %r" % value) continue - yield '%s.%s = property(lambda self:%s.__get__(self.__self__))' % ( - name, key, self.nameof(value)) +# yield '%s.%s = property(lambda self:%s.__get__(self.__self__))' % ( +# name, key, self.nameof(value)) + yield '%s.%s = %s' % (name, key, self.nameof(value)) baseargs = ", ".join(basenames) if baseargs: @@ -561,8 +562,9 @@ a(' __metaclass__ = type') a(' __slots__ = ["__self__"] # for PyCObject') a(' def __new__(cls, *args, **kwds):') - a(' inst = object.__new__(cls)') - a(' inst.__self__ = %s()' % instantiator) - a(' return inst') + a(' return %s()' % instantiator ) + # XXX + # I would like to use instantiator directly, but don't know + # how to create a function that ignores all args self.later(initclassobj()) return name Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Fri Mar 31 10:02:37 2006 @@ -5,6 +5,7 @@ from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype from pypy.rpython.objectmodel import instantiate +from pypy.rpython import robject, rclass P = False # debug printing @@ -103,15 +104,24 @@ def rtype_destruct_object(hop): v_any, c_spec = hop.inputargs(*hop.args_r) repr = c_spec.value - if '_wrapper_' in repr.allinstancefields: + if repr.has_wrapper: null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) + v_wrapper = repr.getfield(v_any, '_wrapper_', hop.llops) + hop.genop('gc_protect', [v_wrapper]) # un-weaken the ref + hop.genop('gc_protect', [v_wrapper]) # don't trigger again! repr.setfield(v_any, '_wrapper_', null, hop.llops) hop.genop('gc_unprotect', [v_any]) def rtype_unwrap_object(hop): + pyptr = hop.args_r[0] + klass = hop.args_s[1].const + classdef = hop.rtyper.annotator.bookkeeper.getuniqueclassdef(klass) + repr = rclass.getinstancerepr(hop.rtyper, classdef, True) v_pyobj, v_type = hop.inputargs(*hop.args_r) - v_adr = hop.llops.gencapicall('PyCObject_AsVoidPtr', [v_pyobj], - resulttype=hop.r_result) + if repr.has_wrapper: + c_self = hop.inputconst(robject.pyobj_repr, '__self__') + v_pyobj = hop.genop('getattr', [v_pyobj, c_self], resulttype=pyptr) + v_adr = hop.llops.gencapicall('PyCObject_AsVoidPtr', [v_pyobj], resulttype=hop.r_result) hop.genop('gc_protect', [v_adr]) return v_adr @@ -119,7 +129,7 @@ v_any, = hop.inputargs(*hop.args_r) repr = hop.args_r[0] c_repr = hop.inputconst(lltype.Void, repr) - if '_wrapper_' in repr.allinstancefields: + if repr.has_wrapper: return hop.gendirectcall(ll_wrap_object, v_any, c_repr) else: return hop.gendirectcall(create_pywrapper, v_any, c_repr) @@ -130,31 +140,38 @@ ret = create_pywrapper(obj, repr) return ret -def create_pywrapper(thing, sr): +def create_pywrapper(thing, repr): return ll_create_pywrapper(thing, sr) -def ll_create_pywrapper(thing, sr): +def ll_create_pywrapper(thing, repr): return 42 -def fetch_pywrapper(thing, sr): - return ll_fetch_pywrapper(thing, sr) +def fetch_pywrapper(thing, repr): + return ll_fetch_pywrapper(thing, repr) -def ll_fetch_pywrapper(thing): +def ll_fetch_pywrapper(thing, repr): return 42 def rtype_wrap_object_create(hop): + gencapi = hop.llops.gencapicall + pyptr = hop.r_result v_any, c_spec = hop.inputargs(*hop.args_r) repr = c_spec.value f = call_destructor hop.genop('gc_protect', [v_any]) - ARGTYPE = repr.lowleveltype + ARG = repr.lowleveltype reprPBC = hop.rtyper.annotator.bookkeeper.immutablevalue(repr) - fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARGTYPE, reprPBC]) - FUNCTYPE = lltype.FuncType([ARGTYPE, lltype.Void], lltype.Void) - c_dtor = hop.inputconst(lltype.Ptr(FUNCTYPE), fp_dtor) - res = hop.llops.gencapicall('PyCObject_FromVoidPtr', [v_any, c_dtor], - resulttype=hop.r_result) - if '_wrapper_' in repr.allinstancefields: + fp_dtor = hop.rtyper.annotate_helper_fn(f, [ARG, reprPBC]) + FUNC = lltype.FuncType([ARG, lltype.Void], lltype.Void) + c_dtor = hop.inputconst(lltype.Ptr(FUNC), fp_dtor) + res = gencapi('PyCObject_FromVoidPtr', [v_any, c_dtor], resulttype=pyptr) + if repr.has_wrapper: + cobj = res + c_cls = hop.inputconst(robject.pyobj_repr, repr.classdef.classdesc.pyobj) + c_0 = hop.inputconst(lltype.Signed, 0) + res = gencapi('PyType_GenericAlloc', [c_cls, c_0], resulttype=pyptr) + c_self = hop.inputconst(robject.pyobj_repr, '__self__') + hop.genop('setattr', [res, c_self, cobj], resulttype=pyptr) repr.setfield(v_any, '_wrapper_', res, hop.llops) hop.genop('gc_unprotect', [res]) # yes a weak ref return res @@ -162,7 +179,7 @@ def rtype_wrap_object_fetch(hop): v_any, c_spec = hop.inputargs(*hop.args_r) repr = c_spec.value - if '_wrapper_' in repr.allinstancefields: + if repr.has_wrapper: return repr.getfield(v_any, '_wrapper_', hop.llops) else: null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) Modified: pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj ============================================================================== --- pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj (original) +++ pypy/dist/pypy/translator/c/winproj/extension/extension.vcproj Fri Mar 31 10:02:37 2006 @@ -208,7 +208,7 @@ + RelativePath="..\..\..\..\..\..\..\Documents and Settings\ctismer\Local Settings\Temp\usession-1496\testing_1\testing_1.c"> From tismer at codespeak.net Fri Mar 31 10:07:57 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 31 Mar 2006 10:07:57 +0200 (CEST) Subject: [pypy-svn] r25176 - pypy/dist/pypy/translator/c/test Message-ID: <20060331080757.53110100D7@code0.codespeak.net> Author: tismer Date: Fri Mar 31 10:07:55 2006 New Revision: 25176 Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py Log: tiny omission Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_wrapping.py (original) +++ pypy/dist/pypy/translator/c/test/test_wrapping.py Fri Mar 31 10:07:55 2006 @@ -106,10 +106,8 @@ repr = c_spec.value if repr.has_wrapper: null = hop.inputconst(lltype.Ptr(lltype.PyObject), lltype.nullptr(lltype.PyObject)) - v_wrapper = repr.getfield(v_any, '_wrapper_', hop.llops) - hop.genop('gc_protect', [v_wrapper]) # un-weaken the ref - hop.genop('gc_protect', [v_wrapper]) # don't trigger again! - repr.setfield(v_any, '_wrapper_', null, hop.llops) + # XXX this is a hack! We need an operation to remove a broken PyObject + repr.setfield(v_any, '_wrapper_', null, hop.llops, opname='bare_setfield') hop.genop('gc_unprotect', [v_any]) def rtype_unwrap_object(hop): @@ -141,7 +139,7 @@ return ret def create_pywrapper(thing, repr): - return ll_create_pywrapper(thing, sr) + return ll_create_pywrapper(thing, repr) def ll_create_pywrapper(thing, repr): return 42 From gromit at codespeak.net Fri Mar 31 15:02:41 2006 From: gromit at codespeak.net (gromit at codespeak.net) Date: Fri, 31 Mar 2006 15:02:41 +0200 (CEST) Subject: [pypy-svn] r25184 - pypy/extradoc/sprintinfo/leysin-winter-2006 Message-ID: <20060331130241.CF4C1100D7@code0.codespeak.net> Author: gromit Date: Fri Mar 31 15:02:11 2006 New Revision: 25184 Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Log: Changed attendance date due to extreme work load. Modified: pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt (original) +++ pypy/extradoc/sprintinfo/leysin-winter-2006/people.txt Fri Mar 31 15:02:11 2006 @@ -22,7 +22,7 @@ Niklaus Haldimann 2/4 - 5/4 Ermina Aurelien Campeas 3/4 - 7/4 Ermina Alexandre Fayolle 3/4 - 7/4 Ermina -Gerald Klix 6/4? - 9/4 Ermina +Gerald Klix 8/4? - 9/4 Ermina (if the short time makes sense) ==================== ============== ===================== People on the following list were present at previous sprints: From goden at codespeak.net Fri Mar 31 18:14:21 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Fri, 31 Mar 2006 18:14:21 +0200 (CEST) Subject: [pypy-svn] r25194 - pypy/dist/pypy/doc Message-ID: <20060331161421.5B05D100D9@code0.codespeak.net> Author: goden Date: Fri Mar 31 18:14:19 2006 New Revision: 25194 Modified: pypy/dist/pypy/doc/svn-help.txt Log: minor clarification as to which section in the subversion config file the "enable-auto-props" option should go. Modified: pypy/dist/pypy/doc/svn-help.txt ============================================================================== --- pypy/dist/pypy/doc/svn-help.txt (original) +++ pypy/dist/pypy/doc/svn-help.txt Fri Mar 31 18:14:19 2006 @@ -136,6 +136,7 @@ In your home directory edit .subversion/config and comment in :: + [miscellany] enable-auto-props = yes [auto-props] From goden at codespeak.net Fri Mar 31 18:23:19 2006 From: goden at codespeak.net (goden at codespeak.net) Date: Fri, 31 Mar 2006 18:23:19 +0200 (CEST) Subject: [pypy-svn] r25195 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20060331162319.73F16100D9@code0.codespeak.net> Author: goden Date: Fri Mar 31 18:23:15 2006 New Revision: 25195 Added: pypy/dist/pypy/rpython/rctypes/rpointer.py (contents, props changed) pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py (contents, props changed) Modified: pypy/dist/pypy/rpython/rctypes/implementation.py pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Log: initial annotation of rctypes pointers using the extregistry Modified: pypy/dist/pypy/rpython/rctypes/implementation.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/implementation.py (original) +++ pypy/dist/pypy/rpython/rctypes/implementation.py Fri Mar 31 18:23:15 2006 @@ -23,6 +23,7 @@ # Importing for side effect of registering types with extregistry import pypy.rpython.rctypes.rarray import pypy.rpython.rctypes.rprimitive +import pypy.rpython.rctypes.rpointer # ctypes_annotation_list contains various attributes that # are used by the pypy annotation. @@ -41,10 +42,10 @@ # (c_ulonglong, UnsignedLongLong, None), # (c_float, Float, None), # (c_double, Float, None), - (c_char_p, None, - staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), - (POINTER(c_char), None, - staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), +# (c_char_p, None, +# staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), +# (POINTER(c_char), None, +# staticmethod(lambda ll_type, arg_name:"RPyString_AsString(%s)" % arg_name)), ] def create_ctypes_annotations(): Added: pypy/dist/pypy/rpython/rctypes/rpointer.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/rpointer.py Fri Mar 31 18:23:15 2006 @@ -0,0 +1,87 @@ +from pypy.rpython.rmodel import Repr +from pypy.rpython import extregistry +from pypy.annotation import model as annmodel + +from ctypes import POINTER, c_int + +class PointerRepr(Repr): + """XXX: todo + """ + def __init__(self, rtyper, ctype, ref_type): + pass + +def get_repr(rtyper, s_pointer): + """XXX: todo + """ + raise RuntimeError("foo") + +def registerPointerType(ptrtype): + """Adds a new pointer type to the extregistry. + + Since pointers can be created to primitive ctypes objects, arrays, + structs and structs are not predefined each new pointer type is + registered in the extregistry as it is identified. + + The new pointers that are created have a "contents" attribute + which, when retrieved, in effect dereferences the pointer and + returns the referenced value. + """ + def compute_result_annotation(s_arg): + return annmodel.SomeCTypesObject(ptrtype, + annmodel.SomeCTypesObject.OWNSMEMORY) + + def specialize_call(hop): + raise RuntimeError('foo') + + type_entry = extregistry.register_type(ptrtype, + specialize_call=specialize_call, + get_repr=get_repr) + contentsType = annmodel.SomeCTypesObject(ptrtype._type_, + annmodel.SomeCTypesObject.MEMORYALIAS) + type_entry.fields_s = {'contents': contentsType} + + return extregistry.register_value(ptrtype, + compute_result_annotation=compute_result_annotation) + +def POINTER_compute_annotation(metatype, the_type): + """compute the annotation of POINTER() calls to create a ctypes + pointer for the given type + """ + + def POINTER_compute_result_annotation(s_arg): + """Called to compute the result annotation of + POINTER(). This happens to return a new + class which itself is treated as SomeBuiltin because when + called it creates a new pointer. + + NOTE: To handle a myriad of possible pointer types, each + ctypes type that is passed to POINTER() calls is itself + registered if it isn't already. + """ + ptrtype = POINTER(s_arg.const) + + if not extregistry.is_registered_type(ptrtype): + entry = registerPointerType(ptrtype) + else: + entry = extregistry.lookup(ptrtype) + + return annmodel.SomeBuiltin(entry.compute_result_annotation, + methodname=ptrtype.__name__) + + # annotation of POINTER (not the call) is SomeBuitin which provides + # a way of computing the result annotation of POINTER() + return annmodel.SomeBuiltin(POINTER_compute_result_annotation, + methodname=the_type.__name__) + +# handles POINTER() calls +value_entry = extregistry.register_value(POINTER, + compute_annotation=POINTER_compute_annotation) + +def POINTER_specialize_call(hop): + raise RuntimeError("foo") + +extregistry.register_type(POINTER, specialize_call=POINTER_specialize_call) + +#type_entry = extregistry.register_type(ptrmeta, +# compute_annotation=compute_annotation, +# get_repr=get_repr) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rctypes.py Fri Mar 31 18:23:15 2006 @@ -266,7 +266,7 @@ t.buildrtyper().specialize() #d#t.view() - def test_compile_simple(self): + def x_test_compile_simple(self): fn = compile(o_atoi, [str]) res = fn("42") assert res == 42 Added: pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py Fri Mar 31 18:23:15 2006 @@ -0,0 +1,63 @@ +""" +Test the rctypes pointer implementation +""" + +import py.test +from pypy.translator.translator import TranslationContext +from pypy import conftest +from pypy.rpython.test.test_llinterp import interpret + +from ctypes import c_int, c_float, POINTER + +import pypy.rpython.rctypes.implementation + +class Test_annotation: + def test_simple(self): + res = c_int(42) + ptrres = POINTER(c_int)(res) + assert res.value == ptrres.contents.value + + def test_annotate_c_int_ptr(self): + def func(): + res = c_int(42) + ptrtype = POINTER(c_int) + ptrres = ptrtype(res) + return ptrres.contents.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + if conftest.option.view: + t.view() + + assert s.knowntype == int + + def test_annotate_c_float_ptr(self): + def func(): + res = c_float(4.2) + ptrtype = POINTER(c_float) + ptrres = ptrtype(res) + return ptrres.contents.value + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(func, []) + + if conftest.option.view: + t.view() + + assert s.knowntype == float + +class Test_specialization: + def x_test_specialize_c_int_ptr(self): + def func(): + res = c_int(42) + ptrtype = POINTER(c_int) + ptrres = ptrtype(res) + + return ptrres.contents.value + + res = interpret(func, []) + + assert res == 42 From arigo at codespeak.net Fri Mar 31 19:25:59 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 31 Mar 2006 19:25:59 +0200 (CEST) Subject: [pypy-svn] r25196 - in pypy/dist/pypy/jit: . test Message-ID: <20060331172559.63F0910088@code0.codespeak.net> Author: arigo Date: Fri Mar 31 19:25:58 2006 New Revision: 25196 Modified: pypy/dist/pypy/jit/hintmodel.py pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py pypy/dist/pypy/jit/test/test_llabstractinterp.py Log: (pedronis, arre, arigo) Pass the next test: propagation of VirtualRedBoxes across links. Modified: pypy/dist/pypy/jit/hintmodel.py ============================================================================== --- pypy/dist/pypy/jit/hintmodel.py (original) +++ pypy/dist/pypy/jit/hintmodel.py Fri Mar 31 19:25:58 2006 @@ -168,6 +168,11 @@ def setfield(hs_v1, hs_fieldname, hs_value): pass + def getsubstruct(hs_v1, hs_fieldname): + S = hs_v1.concretetype.TO + FIELD_TYPE = getattr(S, hs_fieldname.const) + return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE)) + class __extend__(SomeLLAbstractConstant): def hint(hs_c1, hs_flags): Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Fri Mar 31 19:25:58 2006 @@ -32,6 +32,9 @@ def same_constant(self, other): return False + def getallvariables(self, result_gv): + pass + # generic implementation of some operations def op_getfield(self, jitstate, fielddesc): op_args = lltype.malloc(VARLIST.TO, 2) @@ -59,6 +62,14 @@ def getgenvar(self, jitstate): return self.genvar + def getallvariables(self, result_gv): + result_gv.append(self.genvar) + + def copybox(self, newblock, gv_type): + newgenvar = rgenop.geninputarg(newblock, gv_type) + return VarRedBox(newgenvar) + + VCONTAINER = lltype.GcStruct("vcontainer") class ContainerRedBox(RedBox): @@ -116,6 +127,25 @@ boxes[i]) return self.genvar + def getallvariables(self, result_gv): + if self.genvar: + result_gv.append(self.genvar) + else: + for smallbox in self.content_boxes: + smallbox.getallvariables(result_gv) + + def copybox(self, newblock, gv_type): + if self.genvar: + newgenvar = rgenop.geninputarg(newblock, gv_type) + return VarRedBox(newgenvar) + bigbox = VirtualRedBox(self.typedesc) + for i in range(len(bigbox.content_boxes)): + # XXX need a memo for sharing + gv_fldtype = self.typedesc.fielddescs[i].gv_resulttype + bigbox.content_boxes[i] = self.content_boxes[i].copybox(newblock, + gv_fldtype) + return bigbox + def op_getfield(self, jitstate, fielddesc): if self.content_boxes is None: return RedBox.op_getfield(self, jitstate, fielddesc) @@ -137,6 +167,9 @@ def getgenvar(self, jitstate): return self.genvar + def copybox(self, newblock, gv_type): + return self + def ll_fromvalue(value): T = lltype.typeOf(value) gv = rgenop.genconst(value) @@ -435,15 +468,13 @@ return jitstate retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)" -def enter_block(jitstate, redboxes, TYPES): +def enter_block(jitstate, redboxes, types_gv): newblock = rgenop.newblock() incoming = [] for i in range(len(redboxes)): redbox = redboxes[i] - if isinstance(redbox, VarRedBox): - incoming.append(redbox.genvar) - newgenvar = rgenop.geninputarg(newblock, TYPES[i]) - redboxes[i] = VarRedBox(newgenvar) + redbox.getallvariables(incoming) + redboxes[i] = redbox.copybox(newblock, types_gv[i]) rgenop.closelink(jitstate.curoutgoinglink, incoming, newblock) jitstate.curblock = newblock jitstate.curoutgoinglink = lltype.nullptr(rgenop.LINK.TO) Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Fri Mar 31 19:25:58 2006 @@ -372,3 +372,30 @@ insns, res = timeshift(ll_function, [42], [], policy=P_NOVIRTUAL) assert res == 42 assert insns == {} + +def test_red_propagate(): + S = lltype.GcStruct('S', ('n', lltype.Signed)) + def ll_function(n, k): + s = lltype.malloc(S) + s.n = n + if k < 0: + return -123 + return s.n * k + insns, res = timeshift(ll_function, [3, 8], [], policy=P_NOVIRTUAL) + assert res == 24 + assert insns == {'int_lt': 1, 'int_mul': 1} + +def test_red_subcontainer(): + py.test.skip("in-progress") + S = lltype.Struct('S', ('n', lltype.Signed)) + T = lltype.GcStruct('T', ('s', S), ('n', lltype.Float)) + def ll_function(k): + t = lltype.malloc(T) + s = t.s + s.n = k + if k > 0: + k -= 1 + return s.n * k + insns, res = timeshift(ll_function, [7], [], policy=P_NOVIRTUAL) + assert res == 42 + #assert insns == ... in-progress Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Fri Mar 31 19:25:58 2006 @@ -66,7 +66,8 @@ graph = graphs.pop() for block in graph.iterblocks(): for op in block.operations: - insns[op.opname] = insns.get(op.opname, 0) + 1 + if op.opname != 'same_as': + insns[op.opname] = insns.get(op.opname, 0) + 1 for arg in op.args: if isinstance(arg, flowmodel.Constant): if (isinstance(arg.concretetype, lltype.Ptr) and From arigo at codespeak.net Fri Mar 31 22:16:17 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 31 Mar 2006 22:16:17 +0200 (CEST) Subject: [pypy-svn] r25197 - in pypy/dist/pypy: jit jit/test rpython/test Message-ID: <20060331201617.37229100D9@code0.codespeak.net> Author: arigo Date: Fri Mar 31 22:16:16 2006 New Revision: 25197 Modified: pypy/dist/pypy/jit/rtimeshift.py pypy/dist/pypy/jit/test/test_hint_timeshift.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: (arigo, arre, pedronis) intermediate check-in, that's it for today. Modified: pypy/dist/pypy/jit/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/rtimeshift.py (original) +++ pypy/dist/pypy/jit/rtimeshift.py Fri Mar 31 22:16:16 2006 @@ -32,9 +32,15 @@ def same_constant(self, other): return False - def getallvariables(self, result_gv): + def getallvariables(self, jitstate, result_gv): pass + def copybox(self, newblock, gv_type, memo): + try: + return memo[self] + except KeyError: + return self._copybox(newblock, gv_type, memo) + # generic implementation of some operations def op_getfield(self, jitstate, fielddesc): op_args = lltype.malloc(VARLIST.TO, 2) @@ -62,12 +68,13 @@ def getgenvar(self, jitstate): return self.genvar - def getallvariables(self, result_gv): + def getallvariables(self, jitstate, result_gv): result_gv.append(self.genvar) - def copybox(self, newblock, gv_type): + def _copybox(self, newblock, gv_type, memo): newgenvar = rgenop.geninputarg(newblock, gv_type) - return VarRedBox(newgenvar) + memo[self] = newbox = VarRedBox(newgenvar) + return newbox VCONTAINER = lltype.GcStruct("vcontainer") @@ -102,14 +109,7 @@ "A red box that contains (for now) a virtual Struct." def __init__(self, typedesc): - # duplicate the list 'content_boxes', - # and also replace the nested VirtualRedBox - clist = [] - for box in typedesc.content_boxes: - if isinstance(box, VirtualRedBox): - box = VirtualRedBox(box.typedesc) - clist.append(box) - self.content_boxes = clist + self.content_boxes = typedesc.build_content_boxes(self) self.typedesc = typedesc self.genvar = rgenop.nullvar @@ -127,23 +127,29 @@ boxes[i]) return self.genvar - def getallvariables(self, result_gv): + def is_forced(self): + return bool(self.genvar) + + def getallvariables(self, jitstate, result_gv): if self.genvar: result_gv.append(self.genvar) else: for smallbox in self.content_boxes: - smallbox.getallvariables(result_gv) + smallbox.getallvariables(jitstate, result_gv) - def copybox(self, newblock, gv_type): + def _copybox(self, newblock, gv_type, memo): if self.genvar: newgenvar = rgenop.geninputarg(newblock, gv_type) - return VarRedBox(newgenvar) + memo[self] = newbox = VarRedBox(newgenvar) + return newbox bigbox = VirtualRedBox(self.typedesc) + memo[self] = bigbox for i in range(len(bigbox.content_boxes)): # XXX need a memo for sharing gv_fldtype = self.typedesc.fielddescs[i].gv_resulttype bigbox.content_boxes[i] = self.content_boxes[i].copybox(newblock, - gv_fldtype) + gv_fldtype, + memo) return bigbox def op_getfield(self, jitstate, fielddesc): @@ -158,6 +164,53 @@ else: self.content_boxes[fielddesc.fieldindex] = valuebox +class SubVirtualRedBox(RedBox): + + def __init__(self, parentbox, fielddesc): + self.parentbox = parentbox + self.fielddesc = fielddesc + typedesc = fielddesc.inlined_typedesc + self.content_boxes = typedesc.build_content_boxes(self) + + def getgenvar(self, jitstate): + gv = self.parentbox.getgenvar(jitstate) + op_args = lltype.malloc(VARLIST.TO, 2) + op_args[0] = gv + op_args[1] = self.fielddesc.gv_fieldname + genvar = rgenop.genop(jitstate.curblock, 'getsubstruct', op_args, + self.fielddesc.gv_resulttype) + return genvar + + def is_forced(self): + return self.parentbox.is_forced() + + def getallvariables(self, jitstate, result_gv): + if self.is_forced(): + result_gv.append(self.getgenvar(jitstate)) + else: + for smallbox in self.content_boxes: + smallbox.getallvariables(jitstate, result_gv) + + def _copybox(self, newblock, gv_type, memo): + if self.is_forced(): + newgenvar = rgenop.geninputarg(newblock, gv_type) + memo[self] = newbox = VarRedBox(newgenvar) + return newbox + bigbox = SubVirtualRedBox(None, self.fielddesc) + memo[self] = bigbox + gv_parenttype = self.fielddesc.parenttypedesc.gv_ptrtype + parentcopybox = self.parentbox.copybox(newblock, gv_parenttype, memo) + bigbox.parentbox = parentcopybox + typedesc = self.fielddesc.inlined_typedesc + for i in range(len(bigbox.content_boxes)): + # XXX need a memo for sharing + gv_fldtype = typedesc.fielddescs[i].gv_resulttype + bigbox.content_boxes[i] = self.content_boxes[i].copybox(newblock, + gv_fldtype, + memo) + return bigbox + + class ConstRedBox(RedBox): "A red box that contains a run-time constant." @@ -167,7 +220,7 @@ def getgenvar(self, jitstate): return self.genvar - def copybox(self, newblock, gv_type): + def copybox(self, newblock, gv_type, memo): return self def ll_fromvalue(value): @@ -303,23 +356,39 @@ self.PTRTYPE = lltype.Ptr(TYPE) self.gv_type = rgenop.constTYPE(self.TYPE) self.gv_ptrtype = rgenop.constTYPE(self.PTRTYPE) + + def setup(self): self.fielddescs = [StructFieldDesc.make(self.PTRTYPE, name) - for name in TYPE._names] + for name in self.TYPE._names] defls = [] for desc in self.fielddescs: if desc.inlined_typedesc is not None: - defaultbox = VirtualRedBox(desc.inlined_typedesc) + defaultbox = None else: defaultvalue = desc.RESTYPE._defl() defaultbox = ConstRedBox.ll_fromvalue(defaultvalue) defls.append(defaultbox) - self.content_boxes = defls + self.default_boxes = defls + + def build_content_boxes(self, parentbox): + # make a'content_boxes' list based on the typedesc's default_boxes, + # building nested SubVirtualRedBoxes for inlined substructs + clist = [] + for i in range(len(self.fielddescs)): + fielddesc = self.fielddescs[i] + if fielddesc.inlined_typedesc: + box = SubVirtualRedBox(parentbox, fielddesc) + else: + box = self.default_boxes[i] + clist.append(box) + return clist def make(T): try: return StructTypeDesc._type_cache[T] except KeyError: desc = StructTypeDesc._type_cache[T] = StructTypeDesc(T) + desc.setup() return desc make = staticmethod(make) @@ -353,6 +422,7 @@ return cache[args] except KeyError: fdesc = cache[args] = cls(PTRTYPE, *args) + fdesc.setup() return fdesc make = classmethod(make) @@ -373,6 +443,9 @@ else: self.inlined_typedesc = None + def setup(self): + self.parenttypedesc = StructTypeDesc.make(self.PTRTYPE.TO) + def compact_repr(self): # goes in ll helper names return "Fld_%s_in_%s" % (self.fieldname, self.PTRTYPE._short_name()) @@ -380,6 +453,8 @@ def __init__(self, PTRTYPE): assert isinstance(PTRTYPE.TO, lltype.Array) FieldDesc.__init__(self, PTRTYPE, PTRTYPE.TO.OF) + def setup(self): + pass def ll_generate_getfield(jitstate, fielddesc, argbox): if fielddesc.immutable and isinstance(argbox, ConstRedBox): @@ -471,10 +546,11 @@ def enter_block(jitstate, redboxes, types_gv): newblock = rgenop.newblock() incoming = [] + memo = {} for i in range(len(redboxes)): redbox = redboxes[i] - redbox.getallvariables(incoming) - redboxes[i] = redbox.copybox(newblock, types_gv[i]) + redbox.getallvariables(jitstate, incoming) + redboxes[i] = redbox.copybox(newblock, types_gv[i], memo) rgenop.closelink(jitstate.curoutgoinglink, incoming, newblock) jitstate.curblock = newblock jitstate.curoutgoinglink = lltype.nullptr(rgenop.LINK.TO) Modified: pypy/dist/pypy/jit/test/test_hint_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/test/test_hint_timeshift.py (original) +++ pypy/dist/pypy/jit/test/test_hint_timeshift.py Fri Mar 31 22:16:16 2006 @@ -393,9 +393,9 @@ t = lltype.malloc(T) s = t.s s.n = k - if k > 0: - k -= 1 - return s.n * k + if k < 0: + return -123 + return s.n * (k-1) insns, res = timeshift(ll_function, [7], [], policy=P_NOVIRTUAL) assert res == 42 #assert insns == ... in-progress Modified: pypy/dist/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rpbc.py (original) +++ pypy/dist/pypy/rpython/test/test_rpbc.py Fri Mar 31 22:16:16 2006 @@ -1165,6 +1165,22 @@ res = interpret(f, [], type_system=self.ts) assert res == 65*66 + def test_convert_multiple_to_single_method_of_frozen_pbc(self): + py.test.skip("in-progress") + class A: + def meth(self, frmeth): + return frmeth(100) + class B(A): + def meth(self, frmeth): + return frmeth(1000) + fr1 = Freezing(); fr1.x = 65 + fr2 = Freezing(); fr2.x = 66 + def f(): + return A().meth(fr1.mymethod) * B().meth(fr2.mymethod) + + res = interpret(f, [], type_system=self.ts) + assert res == 165 * 1066 + def test_call_from_list(): # Don't test with ootype, since it doesn't support lists in a